Работа с History API
====================

В HTML5 стали доступны методы `pushState()` и `replaceState()` для добавления и изменения записей в истории. Эти методы работают в сочетании с событием `onpopstate` (en-US)

Добавление и изменение записей в истории
----------------------------------------

`pushState()` позволяет изменить referrer, который используется в HTTP-заголовке для `XMLHttpRequest` объектов, созданных после изменения состояния. Значением referrer будет URL документа, окно которого является `this` на момент создания `XMLHttpRequest` объекта.

### Пример метода pushState()

Предположим, на странице `http://mozilla.org/foo.html` выполняется следующий JavaScript-код:


```js
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`.

**Примечание:** Вызов `history.back()` обычно ведёт себя так же, как нажатие на кнопку **"Назад"**. Но есть одно важное исключение:

*После использования* `history.pushState()`, вызов `history.back()` *не вызывает событие* `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 текущего документа.


**Примечание:** Начиная с Gecko 2.0 и до Gecko 5.0, переданный объект сериализуется с помощью JSON. Начиная с Gecko 6.0, объект сериализуется с помощью алгоритма структурированного клонирования. Это позволяет безопасно передавать более широкий спектр объектов.

Вызов `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 текущей записи в истории в ответ на какое-то действие пользователя.

**Примечание:** Начиная с Gecko 2.0 и до Gecko 5.0, переданный объект сериализуется с помощью JSON. Начиная с Gecko 6.0, объект сериализуется с помощью алгоритма структурированного клонирования. Это позволяет безопасно передавать более широкий спектр объектов.

### Пример метода replaceState()

Предположим, на странице `http://mozilla.org/foo.html` выполняется следующий JavaScript-код:


```js
let stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
```


Объяснение этих двух строк можно найти в приведённом выше разделе *пример метода pushState()*.

Далее, предположим, на странице `http://mozilla.org/bar.html` выполняется JavaScript-код:


```js
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` (en-US).

### Чтение текущего состояния

Когда страница загружается, она может иметь объект события со значением, отличным от `"null"`. Это может произойти, например, если страница устанавливает объект состояния (с помощью `pushState()` или `replaceState()`) и затем пользователь перезапускает браузер. Когда страница перезагружается, она получит событие `onload`, но не получит событие `popstate`. Тем не менее, если вы прочитаете свойство `history.state`, получите объект состояния, который получили, если бы произошло событие `popstate`.

С помощью свойства `history.state` можно прочитать состояние текущей записи в истории, не дожидаясь события `popstate`, например:


```js
let currentState = history.state;
```

Смотрите также
--------------

* History API
* Ajax navigation example (en-US)
* `window.history`