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 так же расширяет возможности для программного перемещения по истории браузера. Это позволяет создавать полноценную навигацию в одностраничных приложениях, менять адрес в браузерной строке и все это будет происходить без перезагрузки страницы.