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.*) захватывают всю
оставшуюся часть пути.Для одного маршрута можно назначить несколько функций-обработчиков, которые вызываются последовательно. Это позволяет строить цепочку 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(path) без
callback:
page('/home'); // переход на страницу Home
Важно: библиотека не перезагружает страницу, а меняет URL и вызывает соответствующие обработчики.
Query-параметры доступны через ctx.querystring, но
удобнее использовать URLSearchParams:
page('/products', function(ctx) {
const params = new URLSearchParams(ctx.querystring);
console.log(params.get('category')); // вывод категории продукта
});
page.redirect('/new-path')
или через вызов page('/new-path') внутри обработчика.next(), дальнейшие обработчики не выполняются.page('/old', function(ctx) {
page.redirect('/new');
});
Необработанные маршруты можно ловить через wildcard *
или создавать middleware с проверкой:
page('*', function(ctx) {
if (!routes.includes(ctx.path)) {
console.log('404 — страница не найдена');
}
});
После объявления всех маршрутов обязательно вызывается
page() без аргументов для старта:
page();
popstate и клики на ссылки
для SPA-навигации.page.base('/app') для работы с
приложением в подкаталоге.ctx и вызывать next(), избегая
глобальных изменений.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();