В этом посте я опишу, как настроить современную маршрутизацию и использовать сигналы для реактивного отключения выбранных ссылок.
Сигналы — это просто реализация паттерна "observable". Хотя мы могли бы использовать любую библиотеку для этой цели, мы создадим свою собственную, чтобы обеспечить лучшую наглядность и понимание.
export class Observable {
#callbacks = new Set();
notify() {
for (const fn of this.#callbacks) fn();
}
subscribe(callback) {
this.#callbacks.add(callback);
return () => this.#callbacks.delete(callback); // unsubscribe
}
}
Далее нам нужно будет создать библиотеку маршрутизации для нашего приложения. Реализация маршрутизации в современных браузерах проста и не требует использования сторонних библиотек.
import { update } from "@fusorjs/dom";
import { Observable } from "./observable";
const observable = new Observable();
let route = location.hash;
window.addEventListener(
"popstate",
() => {
route = location.hash;
observable.notify();
},
false
);
export const getRoute = () => route;
export const mountRoute = (self) => observable.subscribe(() => update(self));
Далее нам нужен реактивный компонент ссылки, который изменяет свой DOM-узел с элемента a
на обычный текст, если текущий маршрут совпадает с его собственным маршрутом.
import { span, a } from "@fusorjs/dom/html";
import { mountRoute, getRoute } from "./route";
const RouteLink = (title, route) =>
span(
{ mount: mountRoute }, // enable reactivity
((cache = a({ href: route }, title)) => () =>
getRoute() === route ? title : cache)()
);
Обратите внимание, что в Fusor существует три способа определить HTML-элемент. В приведённом выше примере используются функции span
и a
. Второй способ включает использование JSX.
<span mount={mountRoute}>{(
(cache = <a href={route}>{title}</a>) =>
() => getRoute() === route ? title : cache
)()}</span>
И третий использует функцию h("span", {mount: mountRoute}, ....
.
Свойство mount
позволяет назначить функцию, которая срабатывает, когда элемент присоединяется к DOM. Обратитесь к разделу "Жизненный цикл компонентов" в туториале для получения более подробной информации.
Наконец, мы используем наш компонент для динамического создания списка ссылок и их прикрепления к DOM.
import { getElement } from "@fusorjs/dom";
import { ul, li } from "@fusorjs/dom/html";
import { RouteLink } from "./route-link";
const block = ul(
[...Array(10)].map((_, i) =>
li(RouteLink(`${i}. Section`, `#url-to-${i}-section`))
)
);
document.body.append(getElement(block));
Посмотрите пожалуйста полный рабочий пример.
Репозиторий Fusor.
Спасибо!