Работа с виртуальным DOM

Page.js — это лёгкая библиотека маршрутизации для клиентских приложений на JavaScript. Она позволяет создавать одностраничные приложения (SPA), управлять переходами между страницами и динамически изменять контент без перезагрузки браузера. Основной принцип работы заключается в перехвате изменений URL и вызове соответствующих обработчиков маршрутов.

Базовый синтаксис регистрации маршрутов выглядит так:

page('/home', () => {
  console.log('Главная страница');
});

page('/about', () => {
  console.log('О приложении');
});

page();
  • page(path, callback) — регистрирует маршрут.
  • path — URL-шаблон маршрута, например /users/:id.
  • callback — функция, вызываемая при совпадении маршрута.
  • page() без аргументов запускает обработку текущего URL.

Работа с параметрами маршрутов

Page.js поддерживает динамические сегменты URL. Например:

page('/user/:id', ctx => {
  console.log(ctx.params.id); // Получение значения :id
});
  • ctx.params — объект с параметрами текущего маршрута.
  • Динамические сегменты удобно использовать для страниц профилей, постов или товаров.

Также можно обрабатывать query-параметры:

page('/search', ctx => {
  const query = new URLSearchParams(ctx.querystring);
  console.log(query.get('q')); // Получение значения параметра q
});

Middleware и цепочки вызовов

Page.js поддерживает концепцию middleware — функций, которые выполняются последовательно перед основным обработчиком маршрута:

function auth(ctx, next) {
  if (!ctx.user) {
    page('/login');
  } else {
    next();
  }
}

page('/dashboard', auth, ctx => {
  console.log('Панель управления');
});
  • next() — вызов следующей функции в цепочке middleware.
  • Middleware можно использовать для авторизации, логирования и предварительной загрузки данных.

Интеграция с виртуальным DOM

Page.js прекрасно сочетается с библиотеками виртуального DOM, такими как Snabbdom, React или Preact. Основная идея — при переходе по маршруту обновлять только часть страницы, не перезагружая весь DOM.

Пример с использованием простого виртуального DOM через Snabbdom:

import { init, h } from 'snabbdom';
import classModule from 'snabbdom/modules/class';
import propsModule from 'snabbdom/modules/props';
import styleModule from 'snabbdom/modules/style';

const patch = init([classModule, propsModule, styleModule]);
let container = document.getElementById('app');
let vnode = h('div', 'Загрузка...');

patch(container, vnode);

page('/home', () => {
  vnode = h('div', [
    h('h1', 'Главная'),
    h('p', 'Добро пожаловать на главную страницу')
  ]);
  patch(container, vnode);
});

page('/about', () => {
  vnode = h('div', [
    h('h1', 'О проекте'),
    h('p', 'Информация о приложении')
  ]);
  patch(container, vnode);
});

page();
  • patch(container, vnode) — обновляет DOM на основе нового виртуального узла.
  • Использование виртуального DOM позволяет минимизировать перерисовку страницы, улучшая производительность SPA.

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

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

page('/profile/:id', async ctx => {
  const { default: Profile } = await import('./components/Profile.js');
  const vnode = Profile(ctx.params.id);
  patch(container, vnode);
});
  • Асинхронные маршруты обеспечивают динамическую подгрузку компонентов только при необходимости.
  • Это позволяет строить масштабируемые SPA с минимальной нагрузкой на клиентский браузер.

Управление состоянием и переходами

Page.js предоставляет методы для программного перехода и контроля истории:

page.show('/home'); // Программный переход
page.back();        // Возврат к предыдущему маршруту
page.redirect('/login'); // Перенаправление
  • page.show(path) — инициирует переход по указанному маршруту без перезагрузки страницы.
  • page.redirect(path) — меняет URL и сразу вызывает маршрут, обычно используется для авторизации.
  • page.back() — использует историю браузера для возврата на предыдущий маршрут.

Использование Page.js с современными фреймворками

В React, Preact или Vue Page.js может выступать в роли внешнего роутера. Основная стратегия — держать виртуальный DOM и состояние компонента вне Page.js, а библиотека отвечает только за маршрутизацию:

page('/dashboard', () => render(<Dashboard />, document.getElementById('app')));
page('/settings', () => render(<Settings />, document.getElementById('app')));
page();
  • Такой подход разделяет логическую маршрутизацию и рендеринг компонентов, что облегчает поддержку крупных приложений.
  • Совместимость с виртуальным DOM обеспечивает плавные переходы без перезагрузки страницы и flicker-эффектов.

Работа с вложенными маршрутами

Page.js позволяет создавать маршруты с вложенной структурой, используя middleware для иерархии:

page('/admin', ctx => { console.log('Админка'); });

page('/admin/users', ctx => { console.log('Список пользователей'); });
page('/admin/settings', ctx => { console.log('Настройки админки'); });
  • Вложенные маршруты могут использовать общий middleware, например, проверку прав администратора.
  • Поддержка вложенности позволяет строить сложные интерфейсы с разделением логики.

Эта структура работы с Page.js демонстрирует гибкость маршрутизации в SPA и её естественную интеграцию с виртуальным DOM для динамических интерфейсов. Она позволяет создавать быстрые, масштабируемые и управляемые веб-приложения с минимальными накладными расходами на перерисовку страниц.