Обработчики маршрутов

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


Регистрация маршрутов

Маршрут создаётся с помощью функции page(path, callback), где:

  • path — строка маршрута, например '/about' или '/user/:id'.
  • callback — функция-обработчик, вызываемая при совпадении URL.
page('/about', function(ctx) {
    console.log('Страница About');
});

Параметр ctx (context) содержит всю информацию о текущем маршруте:

  • ctx.path — полный путь текущего URL.
  • ctx.params — объект с параметрами маршрута (/user/:id{ id: '123' }).
  • ctx.querystring — строка запроса после ?.
  • ctx.state — объект для хранения пользовательских данных между middleware.

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

Page.js поддерживает динамические сегменты через :param и опциональные через *:

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

page('/search/*', function(ctx) {
    console.log(ctx.params[0]); // выводит всю подстроку после /search/
});
  • Динамические параметры (:id) автоматически парсятся в ctx.params.
  • Wildcard-параметры (*) захватывают всю оставшуюся часть пути.

Использование нескольких обработчиков

Для одного маршрута можно назначить несколько функций-обработчиков, которые вызываются последовательно. Это позволяет строить цепочку middleware, как в Express:

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

function renderDashboard(ctx) {
    console.log('Рендерим Dashboard для', ctx.state.user);
}

page('/dashboard', auth, renderDashboard);
  • next() — передаёт управление следующему обработчику.
  • Позволяет разделять авторизацию, валидацию, логирование и рендеринг на независимые функции.

Глобальные обработчики

Page.js позволяет создавать обработчики, которые срабатывают на все маршруты с помощью page('*', callback):

page('*', function(ctx, next) {
    console.log('Обрабатываем маршрут:', ctx.path);
    next();
});

Такой подход используется для:

  • Логирования переходов.
  • Общей настройки состояния приложения.
  • Подключения аналитики.

Навигация через Page.js

Для программной навигации используется page(path) без callback:

page('/home'); // переход на страницу Home

Важно: библиотека не перезагружает страницу, а меняет URL и вызывает соответствующие обработчики.


Работа с query-параметрами

Query-параметры доступны через ctx.querystring, но удобнее использовать URLSearchParams:

page('/products', function(ctx) {
    const params = new URLSearchParams(ctx.querystring);
    console.log(params.get('category')); // вывод категории продукта
});
  • Это позволяет извлекать фильтры, сортировки и другие данные из URL.
  • Можно комбинировать с динамическими параметрами.

Отмена маршрутов и редиректы

  • Редирект: page.redirect('/new-path') или через вызов page('/new-path') внутри обработчика.
  • Прерывание цепочки: если middleware не вызывает next(), дальнейшие обработчики не выполняются.
page('/old', function(ctx) {
    page.redirect('/new');
});

Обработка ошибок и нестандартных маршрутов

Необработанные маршруты можно ловить через wildcard * или создавать middleware с проверкой:

page('*', function(ctx) {
    if (!routes.includes(ctx.path)) {
        console.log('404 — страница не найдена');
    }
});
  • Это позволяет реализовать страницу “404” без дополнительного роутера.
  • Можно добавлять проверку авторизации и перенаправление на главную.

Инициализация маршрутов

После объявления всех маршрутов обязательно вызывается page() без аргументов для старта:

page();

Советы по архитектуре обработчиков

  1. Разделение логики: middleware для авторизации, логирования и рендеринга лучше держать отдельно.
  2. Минимизация побочных эффектов: обработчики должны работать с ctx и вызывать next(), избегая глобальных изменений.
  3. Композиция: использование цепочек обработчиков делает код гибким и удобным для масштабирования.
  4. Структурирование параметров: всегда использовать ctx.params и ctx.querystring вместо глобального парсинга URL.

Пример комплексного маршрута

function setUser(ctx, next) {
    ctx.state.user = { name: 'Alice', role: 'admin' };
    next();
}

function checkAdmin(ctx, next) {
    if (ctx.state.user.role !== 'admin') {
        page.redirect('/not-authorized');
    } else {
        next();
    }
}

function renderAdminDashboard(ctx) {
    console.log('Добро пожаловать, администратор:', ctx.state.user.name);
}

page('/admin', setUser, checkAdmin, renderAdminDashboard);
page('/not-authorized', () => console.log('Нет доступа'));
page();
  • Использование нескольких middleware обеспечивает проверку, состояние и рендеринг в последовательности.
  • Любые изменения URL сразу обрабатываются библиотекой без перезагрузки страницы.