Симуляция навигации

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

Ключевые компоненты Page.js:

  • Маршрут — определённый путь URL, на который привязана функция-обработчик.
  • Обработчик маршрута — функция, вызываемая при совпадении URL с маршрутом.
  • Контекст (ctx) — объект, который передаётся обработчику и содержит параметры URL, query-параметры, путь и другие данные.
page('/home', ctx => {
    console.log('Текущий путь:', ctx.path);
});

Настройка и инициализация

Для использования Page.js достаточно подключить библиотеку и вызвать page() с маршрутом. После определения всех маршрутов вызывается page() без аргументов для запуска маршрутизатора.

page('/about', ctx => {
    document.body.textContent = 'Страница "О нас"';
});

page('/contact', ctx => {
    document.body.textContent = 'Страница "Контакты"';
});

page(); // запуск маршрутизатора

По умолчанию Page.js использует HTML5 History API, что позволяет менять URL без перезагрузки страницы. Если браузер не поддерживает pushState, библиотека может использовать хэш-маршрутизацию.


Параметры маршрутов

Маршруты в Page.js поддерживают динамические параметры. Параметры задаются через двоеточие (:), и значения автоматически попадают в объект ctx.params.

page('/user/:id', ctx => {
    console.log(ctx.params.id); // выводит id пользователя
});

Можно использовать несколько параметров в одном маршруте:

page('/post/:category/:id', ctx => {
    console.log(ctx.params.category, ctx.params.id);
});

Для необязательных параметров используется знак вопроса:

page('/archive/:year/:month?', ctx => {
    console.log(ctx.params.year, ctx.params.month); // month может быть undefined
});

Query-параметры и контекст

Page.js не парсит query-параметры автоматически, но их можно получить через ctx.querystring или сторонние утилиты:

page('/search', ctx => {
    console.log(ctx.querystring); // "q=javascript&page=2"
});

Для преобразования query-параметров в объект удобно использовать URLSearchParams:

page('/search', ctx => {
    const params = new URLSearchParams(ctx.querystring);
    console.log(params.get('q')); // "javascript"
});

Контекст маршрута (ctx) содержит:

  • ctx.path — полный путь запроса.
  • ctx.params — объект параметров маршрута.
  • ctx.querystring — строка query-параметров.
  • ctx.title — можно установить заголовок страницы.
  • ctx.state — пользовательские данные, переданные через page.show(path, state).

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

Page.js позволяет менять URL без перезагрузки с помощью функции page.show():

page.show('/about'); // переходит на маршрут "/about"
page.show('/user/123'); // переходит на маршрут с параметром

Можно передавать объект состояния:

page.show('/dashboard', { tab: 'settings' });

При этом состояние будет доступно через ctx.state в обработчике маршрута.


Middleware и цепочка обработки

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

page('*', ctx => {
    console.log('Входящий путь:', ctx.path);
    ctx.user = { name: 'Alice' };
});

page('/profile', ctx => {
    console.log(ctx.user.name); // "Alice"
});

Можно использовать несколько middleware, которые вызываются последовательно:

page('/dashboard', auth, loadData, ctx => {
    renderDashboard(ctx.data);
});

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

function loadData(ctx, next) {
    fetch(`/api/data`).then(res => res.json()).then(data => {
        ctx.data = data;
        next();
    });
}

Симуляция навигации для тестирования

Для тестирования маршрутов без кликов по ссылкам удобно использовать:

page.show('/home'); // инициирует переход
page.dispatch('/home'); // вызывает обработчики маршрута без изменения URL

page.dispatch() полезна, если требуется симулировать навигацию внутри теста, чтобы проверить работу middleware и обработчиков маршрутов.


Работа с ссылками

Page.js может автоматически перехватывать клики по ссылкам <a> с помощью page.start({ click: true }) (по умолчанию click: true). Для этого ссылки должны быть внутренними, относительными, без атрибута target="_blank".

<a href="/about">О нас</a>

При клике страница не перезагрузится, а вызовется соответствующий обработчик маршрута. Для ссылок с внешним переходом можно использовать data-no-page:

<a href="https://example.com" data-no-page>Внешняя ссылка</a>

Асинхронная обработка и промисы

Page.js поддерживает асинхронные операции в middleware через next():

page('/profile', async (ctx, next) => {
    ctx.userData = await fetch(`/api/users/${ctx.params.id}`).then(r => r.json());
    next();
});

Важно вызывать next() после завершения асинхронного кода, иначе маршрутизатор не продолжит цепочку.


Настройка fallback и 404

Для обработки неопределённых маршрутов используется wildcard *:

page('*', ctx => {
    document.body.textContent = 'Страница не найдена';
});

Если использовать middleware до определения конкретных маршрутов, он сработает для всех переходов.


Примеры сложной конфигурации

page('*', logger);
page('/login', loginHandler);
page('/dashboard', auth, loadDashboard);
page('/dashboard/settings', auth, loadSettings);
page('/user/:id', auth, loadUserProfile);
page('*', notFound);

page();

function logger(ctx, next) {
    console.log('Переход на:', ctx.path);
    next();
}

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

В этом примере реализована цепочка middleware, авторизация, динамические параметры и глобальный логгер.


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