Работа с History API
В HTML5 стали доступны методы pushState()
и replaceState()
для добавления и изменения записей в истории. Эти методы работают в сочетании с событием onpopstate
Добавление и изменение записей в истории
pushState()
позволяет изменить referrer, который используется в HTTP-заголовке для XMLHttpRequest
объектов, созданных после изменения состояния. Значением referrer будет URL документа, окно которого является this
на момент создания XMLHttpRequest
объекта.
Пример метода pushState()
Предположим, на странице http://mozilla.org/foo.html
выполняется следующий JavaScript-код:
let stateObj = {
foo: "bar",
};
history.pushState(stateObj, "page 2", "bar.html");
В результате этого в URL-строке отобразится адрес http://mozilla.org/bar.html
, но браузер не будет загружать страницу bar.html
и даже не будет проверять, существует ли она..
Теперь предположим, что пользователь перешёл по адресу http://google.com
и затем нажал на кнопку "Назад". В результате этого в URL будет отображаться http://mozilla.org/bar.html
, а history.state
будет содержать stateObj
. Событие popstate не будет вызвано, поскольку страница была перезагружена. Сама страница будет выглядеть как bar.html
.
Если пользователь ещё раз нажимает кнопку "Назад", URL изменится на http://mozilla.org/foo.html
, а в документе снова произойдёт событие popstate
, на этот раз с объектом состояния, имеющим значение null
. В этом случае возврат назад также не меняет содержимое документа, как и на предыдущем шаге, хотя документ может сам обновить своё содержимое после получения события popstate
.
Метод pushState()
Метод pushState()
принимает три параметра: объект состояния, заголовок (в данный момент игнорируется) и (необязательно) параметр "URL".
Давайте более подробно рассмотрим каждый и этих трёх параметров.
- state object
-
Объект состояния – это JavaScript-объект, связанный с новой записью в истории, созданной
pushState()
. Всякий раз, когда пользователь переходит к новому состоянию, происходит событиеpopstate
, а свойствоstate
этого события содержит копию объекта состояния с записями истории.Объект состояния может быть чем-угодно, что может быть сериализовано. Поскольку Firefox сохраняет объекты состояния на диске пользователя, чтобы их можно было восстановить после перезапуска браузера, мы накладываем ограничение в 640 тысяч символов на сериализованное представление объекта состояния. Если вы передаёте объект состояния, чьё сериализованное представление больше этого значения, метод
pushState()
выдаст исключение. Если вам нужно хранилище большего размера, следует рассмотреть использованиеsessionStorage
и/илиlocalStorage
. - title
-
Заголовок - все браузеры, кроме Safari, на данный момент игнорируют этот параметр, но могут начать использовать в будущем. Ввиду будущих изменений метода, безопасным решением является передача пустой строки. В качестве альтернативы вы можете передать короткий заголовок для состоянии, в которое переходите.
- URL
-
Через этот параметр передаётся URL-адрес новой новый записи в истории. Обратите внимание, что браузер не будет пытаться загрузить данный URL сразу после вызова
pushState()
, но может попытаться сделать это позже, например, после того, как пользователь перезапустит браузер. Новый URL-адрес не обязан быть абсолютным; если он относительный, то определяется относительно текущего URL. Новый URL должен вести на тот же домен, протокол и порт, иначеpushState()
выдаст исключение. Данный параметр не является обязательным; если он не указан, будет использоваться URL текущего документа.
Вызов pushState()
в некоторой степени похож на установку window.location = "#foo"
, поскольку они оба также создают и активируют ещё одну запись в истории, связанную с текущим документом.
Но у pushState()
есть несколько преимуществ:
- Новый URL может быть любым в пределах того же домена, порта и протокола, что и текущий адрес. Тогда как настройка
window.location
оставляет вас на том жеdocument
лишь в том случае, если вы меняете только хэш - Менять URL не обязательно. Тогда как настройка
window.location = "#foo";
создаёт новую запись в истории, только если текущий хеш не#foo
- С новой записью в истории можно связать любые данные. В подходе, основанном на хеше, все соответствующие данные нужно кодировать в короткую строку
- Если заголовок
title
впоследствии используется браузерами, эти данные могут быть использованы (независимо от, скажем, хеша).
Обратите внимание, что pushState()
никогда не вызывает событие hashchange
, даже если новый URL отличается от старого только хешем.
В XUL-документах он создаёт указанный XUL-элемент
В других документах он создаёт элемент с null namespace URI.
Метод replaceState()
history.replaceState()
работает точно так же, как history.pushState()
, за исключением того, что replaceState()
изменяет текущую запись истории вместо создания новой записи. Обратите внимание, что он не предотвращает создание новой записи в глобальной истории браузера.
replaceState()
особенно полезен, когда вы хотите обновить объект состояния или URL текущей записи в истории в ответ на какое-то действие пользователя.
Пример метода replaceState()
Предположим, на странице http://mozilla.org/foo.html
выполняется следующий JavaScript-код:
let stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
Объяснение этих двух строк можно найти в приведённом выше разделе пример метода pushState().
Далее, предположим, на странице http://mozilla.org/bar.html
выполняется JavaScript-код:
history.replaceState(stateObj, "page 3", "bar2.html");
Это приведёт к тому, что в URL-строке отобразится адрес http://mozilla.org/bar2.html
, но браузер не станет сразу загружать bar2.html
и даже не станет проверять наличие этой страницы bar2.html
.
Теперь предположим, что пользователь переходит по адресу http://www.microsoft.com
, а затем нажимает на кнопку "Назад". В этом случае в URL-строке отобразится http://mozilla.org/bar2.html
. Если же пользователь снова нажмёт на кнопку "Назад", в URL-строке отобразится http://mozilla.org/foo.html
и полностью обойдёт bar.html
.
Событие popstate
Событие popstate
вызывается в окне каждый раз, когда активная запись в истории меняется. Если запись в истории, которая активируется, была создана с помощью вызова pushState
или активирована вызовом replaceState
, свойство state
события popstate
содержит копию записи в истории объекта события.
Примеры использования можно посмотреть в Window.onpopstate
.
Чтение текущего состояния
Когда страница загружается, она может иметь объект события со значением, отличным от "null"
. Это может произойти, например, если страница устанавливает объект состояния (с помощью pushState()
или replaceState()
) и затем пользователь перезапускает браузер. Когда страница перезагружается, она получит событие onload
, но не получит событие popstate
. Тем не менее, если вы прочитаете свойство history.state
, получите объект состояния, который получили, если бы произошло событие popstate
.
С помощью свойства history.state
можно прочитать состояние текущей записи в истории, не дожидаясь события popstate
, например:
let currentState = history.state;