Программная навигация

Haunted — это библиотека для создания веб-компонентов на базе функционального подхода и хуков, вдохновлённых React. Её ключевое преимущество — возможность управлять состоянием компонентов через чистые функции, что облегчает построение сложных интерфейсов. Программная навигация в Haunted подразумевает управление переходами между «страницами» или состояниями приложения без перезагрузки страницы, используя JavaScript и встроенные возможности браузера.


Работа с состоянием и хуками

Haunted предоставляет несколько хуков, среди которых наиболее важные для навигации:

  • useState — позволяет хранить локальное состояние компонента.
  • useEffect — позволяет выполнять побочные эффекты, например синхронизацию URL или изменение истории браузера.
  • useRef — хранит ссылки на DOM-элементы для управления фокусом или прокруткой при переходах.

Пример базового состояния для маршрутизации:

import { html, component } from 'haunted';
import { useState, useEffect } from 'haunted';

function App() {
  const [route, setRoute] = useState(window.location.pathname);

  useEffect(() => {
    const onPopSt ate = () => setRoute(window.location.pathname);
    window.addEventListener('popstate', onPopState);
    return () => window.removeEventListener('popstate', onPopState);
  }, []);

  const navigate = (path) => {
    window.history.pushState({}, '', path);
    setRoute(path);
  };

  return html`
    <nav>
      <button @click=${() => navigate('/')}>Главная</button>
      <button @click=${() => navigate('/about')}>О нас</button>
    </nav>
    <main>
      ${route === '/' ? html`<home-page></home-page>` : html`<about-page></about-page>`}
    </main>
  `;
}

customElements.define('app-root', component(App));

Ключевые моменты:

  • window.history.pushState позволяет изменять URL без перезагрузки.
  • popstate отслеживает изменения истории браузера.
  • Состояние route определяет, какой компонент отображается.

Организация маршрутов

Haunted не содержит встроенной системы маршрутизации, поэтому маршруты обычно реализуются вручную или через лёгкие библиотеки. Основные подходы:

  1. Статическая маршрутизация — простой объект с сопоставлением пути и компонента:
const routes = {
  '/': html`<home-page></home-page>`,
  '/about': html`<about-page></about-page>`,
};

function Router({ route }) {
  return routes[route] || html`<not-found></not-found>`;
}
  1. Динамические маршруты — использование регулярных выражений для параметров URL:
const routes = [
  { pattern: /^\/user\/(\d+)$/, render: (id) => html`<user-profile .id=${id}></user-profile>` },
];

function Router({ route }) {
  for (const { pattern, render } of routes) {
    const match = route.match(pattern);
    if (match) return render(match[1]);
  }
  return html`<not-found></not-found>`;
}

Преимущества динамических маршрутов: возможность извлекать параметры из URL без сторонних библиотек.


Состояние истории и управление навигацией

Важным аспектом является синхронизация состояния приложения с историей браузера. Использование history.pushState и history.replaceState позволяет:

  • Создавать новые записи истории при переходах.
  • Замещать текущую запись без добавления в стек истории (например, при исправлении URL без навигации).

Пример:

function navigate(path, replace = false) {
  if (replace) {
    window.history.replaceState({}, '', path);
  } else {
    window.history.pushState({}, '', path);
  }
  setRoute(path);
}

Это обеспечивает полную поддержку кнопок «Назад» и «Вперёд» в браузере.


Анимации и прокрутка при переходах

Для плавной навигации и улучшения UX важно управлять прокруткой и анимациями при смене маршрутов.

useEffect(() => {
  window.scrollTo({ top: 0, beh * avior: 'smooth' });
}, [route]);
  • Каждый раз при смене route страница прокручивается наверх.
  • Можно использовать дополнительные хуки для анимации появления новых компонентов.

Асинхронная загрузка компонентов

Haunted поддерживает ленивую загрузку компонентов через динамический import(). Это полезно для крупных приложений:

async function loadPage(route) {
  switch(route) {
    case '/about':
      await import('./about-page.js');
      return html`<about-page></about-page>`;
    default:
      await import('./home-page.js');
      return html`<home-page></home-page>`;
  }
}
  • Асинхронная загрузка снижает первоначальный вес приложения.
  • Можно комбинировать с Skeleton-компонентами для отображения загрузки.

Программная навигация в событиях

Haunted позволяет навигировать программно не только через кнопки, но и через события:

document.addEventListener('navigate', (e) => navigate(e.detail.path));
  • Создание пользовательских событий делает маршрутизацию гибкой.
  • Компоненты могут запускать навигацию без прямой зависимости от родителя.

Взаимодействие с внешними библиотеками маршрутизации

Haunted легко интегрируется с лёгкими роутерами, например Navigo или Page.js. Основной подход:

  • Инициализация роутера при монтировании корневого компонента.
  • Обновление состояния Haunted через колбэк роутера.
useEffect(() => {
  const router = new Navigo('/');
  router.on('/about', () => setRoute('/about'));
  router.on('/', () => setRoute('/'));
  router.resolve();
}, []);

Это позволяет сочетать декларативное управление состоянием Haunted с проверенной маршрутизацией сторонней библиотеки.


Haunted сочетает минимализм веб-компонентов с современными подходами к программной навигации, обеспечивая гибкость в управлении состоянием, маршрутизацией и асинхронной загрузкой страниц. Это делает его подходящим инструментом для построения SPA без лишнего шума и зависимости от крупных фреймворков.