JavaScript и jQuery / window.history

Заметка создана: 07 февраля 2025 г.

History API даёт доступ к управлению историей браузера в рамках текущей сессии. Браузер создаёт новую сессию, когда пользователь открывает новую вкладку или новое окно браузера.

С помощью History API можно переходить по истории вперёд, назад и управлять содержимым истории. Доступ к API осуществляется с помощью объекта window.history.

Основные методы:

  • back() перемещает пользователя по истории на страницу назад;
  • forward() перемещает пользователя по истории на страницу вперёд;
  • go() универсальный метод для перемещения по истории вперёд или назад;
  • pushState() добавляет новую запись в истории сессии;
  • replaceState() изменяет текущую запись в истории сессии.


Как пишется

Сгруппируем методы и свойства History API на две части:

  • используемые для перемещения по истории в текущей сессии.
  • используемые для управления историей.

Перемещение по истории браузера

Метод back() перемещает пользователя по истории назад. Это работает аналогично нажатию кнопки «Назад» в браузере.

Метод back() не принимает аргументов и не возвращает результата.

window.history.back()

Чтобы переместиться по истории вперёд, используется метод forward(). Он работает аналогично кнопке «Вперёд» в браузере.

Метод forward() не принимает аргументов и не возвращает результата.

window.history.forward()

Метод go() является универсальным и позволяет переместиться по истории вперёд или назад относительно текущей страницы.

Метод принимает один аргумент — число, которое определяет, на сколько шагов по истории вперёд или назад нужно перейти. Отрицательное значение определяет сколько шагов назад, а положительные — вперёд.

window.history.go(2)
// переместит на две позиции вперёд по истории

window.history.go(-1)
// переместит назад на одну страницу

Нулевая позиция 0 означает текущую страницу и вызов с нулём обновляет текущую страницу.

window.history.go(0)

Метод back() аналогичен вызову window.history.go(-1), а метод forward() — вызову window.history.go(1).

Все методы для перемещения по истории браузера back(), forward() и go() являются асинхронными.

О том для чего вообще может понадобиться передавать данные во время навигации смотрите раздел «На практике».
Свойство length хранит количество записей в истории браузера в текущей сессии, включая текущую страницу. То есть новая история всегда будет начинаться с 1.

length работает только для чтения, при изменении значения ничего не произойдёт.

Управление историей

Для создания новой записи в истории используется метод pushState(), а для модификации текущей записи — replaceState().

Оба метода похожи с точки зрения использования и оба принимают три аргумента:

  • объект состояния, в который можно добавить любые данные, необходимые для навигации;
  • неиспользуемый параметр, который существует по историческим причинам;
  • новый URL-адрес, этот параметр опциональный.

У передаваемых аргументов есть ограничения, о которых стоит помнить:

  • В первый аргумент-объект можно записать любой объект с любыми данными, главное чтобы объект был сериализуемым. Браузеры могут накладывать ограничения на размер такого объекта.
  • Второй аргумент игнорируется всеми браузерами кроме Safari. Во избежание ошибок рекомендуют передавать пустую строку.
  • Третий аргумент, URL-адрес, необязательный. Если этот аргумент не был задан, то будет использован текущий URL. Новый URL-адрес должен использовать тот же протокол, домен и порт, иначе будет выброшена ошибка. Если новая запись ведёт на новый относительный адрес, то можно не передавать адрес полностью вместе с доменом, а записать только относительную часть через слэш. Например, /profile.

    О том для чего вообще может понадобиться передавать данные во время навигации смотрите раздел «На практике».
    Рассмотрим работу window.history на примере. В этом примере у нас получится замкнутый круг переходов по страницам. Вы можете поиграться с примером, ниже я разберу код, который используется в демке.

Предположим, что мы зашли на главную страницу сайта с новой вкладки. С помощью кнопки добавим новую запись в историю:

window.history.pushState(
  {},
  '',
  'about.html'
)

Адрес в браузерной сроке location.path изменился, а так же обновилось количество записей в истории history.length. Теперь если нажать кнопку перезагрузки страницы, то мы увидим новую страницу.

Теперь можем изменить текущую запись в истории, нажав на кнопку. Ниже приведён фрагмент код, который делает изменение истории:

window.history.replaceState(
  {},
  '',
  'index.html'
)

Адрес в браузерной строке снова изменился, но количество записей осталось прежним, так как мы ничего не добавили. Далее продолжаем путь на следующую страницу.

Страница цен является последним пунктом в примере, с него можно только вернуться по истории назад на предыдущую страницу.

window.history.back()
// Или можно сделать window.history.go(-1)


Помните, как на предыдущей странице видели страницу «О нас» по ссылке about.html? Мы же попали на главную страницу. Это произошло потому что мы изменили текущую запись в истории, изменив её URL-адрес. В результате, когда мы возвращаемся назад по истории, то используем изменённый URL.

Как понять

Классическая навигация

Основным способом в вебе навигации являются ссылки <a>. С помощью ссылок страницы соединяются друг с другом.

Особенность этого способа навигации в том, что при переходе на новый адрес страница перезагружается. Каждый такой переход сохраняется в истории браузера. История может выглядеть так:


https://example.com/buy
https://example.com/prices
https://example.com/about
https://example.com/

Верхние пункты списка — это недавно посещённые страницы, а последний пункт — страница, с которой началась сессия.

Навигация в одностраничных приложениях

С другой стороны, есть одностраничные приложения, которые работают без перезагрузки страницы. Все содержимое они отрисовывают с помощью JavaScript. Приложение может перерисовать всю страницу, но на истории браузера это никак не отобразится.

История в браузере будет выглядеть как единственный пункт:

https://example.com/

Это ведёт к плохому пользовательскому опыту, потому что пользователю сложно понять по каким страницам он перемещался.

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

Сначала эту проблему решали добавлением хэша в адрес сайта с помощью поля window.location.hash. Присвоив новое значение в location.hash, адресная строка сразу же обновлялась и в историю добавлялась новая запись. Но с помощью хэша нельзя строить читаемые многоуровневые урлы, например https://example.com/category/cars/item/12345.

С появлением History API появилась возможность напрямую добавлять записи в историю просмотров. History API так же расширяет возможности для программного перемещения по истории браузера. Это позволяет создавать полноценную навигацию в одностраничных приложениях, менять адрес в браузерной строке и все это будет происходить без перезагрузки страницы.