Определение навигации вперед/назад с pushstate API в HTML5

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

JS
Скопировать код
history.state?.source === 'back' || history.state?.source === 'forward'

Для того чтобы выяснить, ассоциируется ли событие popstate с действиями Назад или Вперёд, стоит проверить, существует ли свойство source в объекте history.state. Важно не забыть присвоить значения 'back' или 'forward' свойству source при работе с history.pushState.

Пример:

JS
Скопировать код
// При добавлении состояния укажите направление,
// чтобы пользователь не терял себя в навигации
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}`); // Выведет 'Переход назад' или 'Переход вперёд'
  }
});

Таким способом, мы контролируем направление навигации, обеспечивая эффективное отслеживание.

Кинга Идем в IT: пошаговый план для смены профессии

Дополняем отслеживание с помощью UID

Для более точного определения направления можно воспользоваться уникальными идентификаторами с автоинкрементом (UID). Добавление такого компонента в состояние поможет сохранить последовательность навигационных изменений и точно определить направление движения.

Добавляем уникальные инкрементируемые ID в состояние

Каждому новому состоянию присваивается уникальный UID:

JS
Скопировать код
let currentUid = -1; // Начинаем с отрицательного числа – почему бы и нет?

// Каждое новое состояние должно иметь свой UID!
function pushStateWithUid(state, title, url) {
  const uid = ++currentUid; // Каждое новое состояние получает свой уникальный идентификатор
  history.pushState({ ...state, uid }, title, url);
}

Используем 'onpopstate' для определения направления

С помощью обработчика событий onpopstate мы можем уйаснить направление:

JS
Скопировать код
window.addEventListener('popstate', function(event) {
  const direction = event.state.uid > currentUid ? 'forward' : 'back';
  currentUid = event.state.uid; // Обновляем текущий UID
  console.log(`Переход ${direction}`);
});

Важно помнить, что не все записи истории будут эффективно работать с этим методом отслеживания, особенно если они идут с других страниц.

Визуализация

Давайте проведём визуализацию отслеживания направления:

Markdown
Скопировать код
🖥️ История браузера: [Главная ➡️ Страница 1 ➡️ Страница 2 ➡️ Страница 3]

Перемещение назад и вперёд можно сравнить со способом перемотки назад ⏮️ и вперёд ⏭️ в истории браузера:

plaintext
Скопировать код
Действие назад: 🔄 Возврат к предыдущей странице
Действие вперед: ⏩ Переход к следующей странице
Markdown
Скопировать код
Ваше местоположение: Страница 2
🔄 Страница 1  [? <- Здесь вы находитесь -> ?] ⏩ Страница 3

Хоть событие popstate само по себе и не указывает направление, его можно указать, просто анализируя изменения в длине истории.

Markdown
Скопировать код
🧮 Анализ нами изменений в истории:
- [Назад] Длина истории сокращается: с 3 до 2
- [Вперёд] Длина истории возрастает: с 2 до 3

Точное определение направления с помощью Math.sign

Для точного определения направления движения используйте функцию Math.sign:

Определение позиции с помощью Math.sign

Внесём улучшения в работу с позициями:

JS
Скопировать код
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 для определения направления
});

Не забывайте, что записи истории, которые появились при переходе с других страниц, могут потребовать особого подхода, и в истории браузера могут быть свои особенности!

Маркировка истории для более наглядной навигации

Вводите временные метки или уникальные идентификаторы для меток каждого изменения в истории, чтобы навигация была более понятной:

Пример маркировки истории

Введём временные метки в состояние для достижения большей точности определения:

JS
Скопировать код
function pushStateWithTimeStamp(state, title, url) {
  const timeStamp = Date.now();
  history.pushState({ ...state, timeStamp }, title, url);
}

Обработка событий с указанием меток времени

На каждом событии popstate сравнивайте временные метки, чтобы ясно понимать направление навигации.

Полезные материалы

  1. Window: событие popstate – Веб-API | MDN — незаменимый источник информации о работе с событием popstate в JavaScript.
  2. History API – Веб-API | MDN — всё, что вам нужно знать о управлении историей браузера с помощью History API.
  3. ASP.NET MVC проверка уникальности – Stack Overflow — подробное изложение темы определения действий кнопок "Назад" и "Вперёд".
  4. History API – Погружение в HTML5 — глубокий анализ работы с состояниями и историей через HTML5 pushState.
  5. GitHub – browserstate/history.jspolyfill для поддержки работы pushState HTML5 в разных браузерах.
  6. Стандарт HTML — всеобъемлющий гайд по безопасности и практическому использованию HTML5 History API.