Определение навигации вперед/назад с pushstate API в HTML5
Быстрый ответ
history.state?.source === 'back' || history.state?.source === 'forward'
Для того чтобы выяснить, ассоциируется ли событие popstate с действиями Назад или Вперёд, стоит проверить, существует ли свойство source
в объекте history.state
. Важно не забыть присвоить значения 'back' или 'forward' свойству source при работе с history.pushState
.
Пример:
// При добавлении состояния укажите направление,
// чтобы пользователь не терял себя в навигации
function pushStateWithSource(state, title, url, source) {
history.pushState({ ...state, source }, title, url);
}
// Задаём направление как 'назад' или 'вперёд'
// Это можно сравнить с тем, как если бы вы дали пользователю компас
pushStateWithSource({}, '', 'nextpage.html', 'forward');
// Отслеживаем событие popstate
window.addEventListener('popstate', function(event) {
// По событию можем определить, в каком направлении двигался пользователь
if(event.state?.source === 'back' || event.state?.source === 'forward') {
console.log(`Переход ${event.state.source}`); // Выведет 'Переход назад' или 'Переход вперёд'
}
});
Таким способом, мы контролируем направление навигации, обеспечивая эффективное отслеживание.
Дополняем отслеживание с помощью UID
Для более точного определения направления можно воспользоваться уникальными идентификаторами с автоинкрементом (UID). Добавление такого компонента в состояние поможет сохранить последовательность навигационных изменений и точно определить направление движения.
Добавляем уникальные инкрементируемые ID в состояние
Каждому новому состоянию присваивается уникальный UID:
let currentUid = -1; // Начинаем с отрицательного числа – почему бы и нет?
// Каждое новое состояние должно иметь свой UID!
function pushStateWithUid(state, title, url) {
const uid = ++currentUid; // Каждое новое состояние получает свой уникальный идентификатор
history.pushState({ ...state, uid }, title, url);
}
Используем 'onpopstate' для определения направления
С помощью обработчика событий onpopstate мы можем уйаснить направление:
window.addEventListener('popstate', function(event) {
const direction = event.state.uid > currentUid ? 'forward' : 'back';
currentUid = event.state.uid; // Обновляем текущий UID
console.log(`Переход ${direction}`);
});
Важно помнить, что не все записи истории будут эффективно работать с этим методом отслеживания, особенно если они идут с других страниц.
Визуализация
Давайте проведём визуализацию отслеживания направления:
🖥️ История браузера: [Главная ➡️ Страница 1 ➡️ Страница 2 ➡️ Страница 3]
Перемещение назад и вперёд можно сравнить со способом перемотки назад ⏮️ и вперёд ⏭️ в истории браузера:
Действие назад: 🔄 Возврат к предыдущей странице
Действие вперед: ⏩ Переход к следующей странице
Ваше местоположение: Страница 2
🔄 Страница 1 [? <- Здесь вы находитесь -> ?] ⏩ Страница 3
Хоть событие popstate само по себе и не указывает направление, его можно указать, просто анализируя изменения в длине истории.
🧮 Анализ нами изменений в истории:
- [Назад] Длина истории сокращается: с 3 до 2
- [Вперёд] Длина истории возрастает: с 2 до 3
Точное определение направления с помощью Math.sign
Для точного определения направления движения используйте функцию Math.sign:
Определение позиции с помощью Math.sign
Внесём улучшения в работу с позициями:
let currentPosition = 0; // Начнём с начальной точки
// Продолжаем добавлять новые состояния
function pushStateWithPosition(state, title, url) {
history.pushState({ ...state, position: ++currentPosition }, title, url);
}
window.addEventListener('popstate', function(event) {
const direction = Math.sign(event.state.position – currentPosition);
currentPosition = event.state.position; // Обновляем текущую позицию
const directionText = direction === 1 ? 'вперёд' : (direction === -1 ? 'назад' : 'неизвестно');
console.log(`Переход ${directionText}`); // Используем Math.sign для определения направления
});
Не забывайте, что записи истории, которые появились при переходе с других страниц, могут потребовать особого подхода, и в истории браузера могут быть свои особенности!
Маркировка истории для более наглядной навигации
Вводите временные метки или уникальные идентификаторы для меток каждого изменения в истории, чтобы навигация была более понятной:
Пример маркировки истории
Введём временные метки в состояние для достижения большей точности определения:
function pushStateWithTimeStamp(state, title, url) {
const timeStamp = Date.now();
history.pushState({ ...state, timeStamp }, title, url);
}
Обработка событий с указанием меток времени
На каждом событии popstate сравнивайте временные метки, чтобы ясно понимать направление навигации.
Полезные материалы
- Window: событие popstate – Веб-API | MDN — незаменимый источник информации о работе с событием popstate в JavaScript.
- History API – Веб-API | MDN — всё, что вам нужно знать о управлении историей браузера с помощью History API.
- ASP.NET MVC проверка уникальности – Stack Overflow — подробное изложение темы определения действий кнопок "Назад" и "Вперёд".
- History API – Погружение в HTML5 — глубокий анализ работы с состояниями и историей через HTML5 pushState.
- GitHub – browserstate/history.js — polyfill для поддержки работы pushState HTML5 в разных браузерах.
- Стандарт HTML — всеобъемлющий гайд по безопасности и практическому использованию HTML5 History API.