История браузера. Объект history в JavaScript

Содержание:
  1. Что такое HTML5 History API?
  2. Зачем вообще нужен объект history?
  3. Назначение объекта history
  4. Свойства, методы и события объекта history
  5. Комментарии

На этом уроке мы познакомимся с объектом history, который отвечает за кнопки "Назад" и "Вперёд", расположенные в окне браузера.

Что такое HTML5 History API?

HTML5 History API – это программный интерфейс, посредством которого у нас имеется доступ к истории браузера. В JavaScript он реализован через глобальный объект window.history.

JavaScript
window.history
// если текущий контекст является window, то обратиться к нему можно просто с помощью history
history

Познакомиться с возможностями этого API чень просто. Для этого достаточно открыть в браузере «Консоль JavaScript» (Ctrl + Shift + J) и ввести команду history. В прототипе этого объекта мы увидим все методы, которые нам доступны для работы с историей:

Методы объекта history

Каждая вкладка в браузере имеет свой объект history. С помощью него мы можем перемещаться по истории, добавлять в неё элементы, реагировать на переходы и делать ещё некоторые вещи.

В браузере история представлена с помощью кнопок «Назад» и «Вперед». С помощью них мы можем перемещаться по истории одного таба.

Кнопки «назад» и «вперед» для перемещения по истории одного таба в браузере

Таким образом, когда мы, например, переходим по ссылке на какую-то другую страницу, которая открывается в этой же вкладе, то у нас она автоматически добавляется в историю. Теперь в history будут 2 страницы: текущая и предыдущая. Вернуться на предыдущую страницу можно с помощью кнопки «Назад», а с предыдущей на следующую посредством «Вперед». Если перейти ещё на какую-то страницу, то в истории их уже будет 3.

В JavaScript получить количество элементов в истории можно с помощью свойства length:

JavaScript
history.length // 3

Перемещаться по истории в JavaScript осуществляется посредством методов back() и forward():

JavaScript
// перейти к предыдущей странице
history.back()
// перейти к следующей странице
history.forward()

Эти методы действуют точно так же, как если бы пользователь нажал соответсвенно на кнопку «Назад» и «Вперед».

JavaScript позволяет так же переместиться сразу на указанное количество шагов по истории. Осуществляется это с помощью метода go():

JavaScript
// на 2 страницы назад
history.go(-2)
// на предыдущую
history.go(-1) // аналогично history.back()
// на 2 страницы вперёд
history.go(2)
// на следующую
history.go(1) // аналогично history.forward()

Вызов метода go() без аргументов или с передачей ему значения (0) приведёт к обновлению страницы:

JavaScript
history.go()
// или
history.go(0)

Зачем вообще нужен объект history?

С приходом AJAX, мы можем обновлять страницу сайта или веб-приложения на основании данных с сервера без её перезагрузки. Но, как при этом нам отобразить это состояние в URL не перезагружая её?

Например, у нас имеется страница на которой мы сделали постраничную навигацию. При клике на кнопку с номером «2», мы с сервера загрузили новые данные и обновили на основании них часть страницы посредством JavaScript:

Здесь показана 2 страница постраничной навигации, но URL-адрес остался текущий

Но если поделиться ссылкой на эту страницу или обновить её, то мы не увидим эти изменения. У нас опять будет отображаться страница с номером «1». То есть наш текущий адрес http://127.0.0.1:5500/index.html не соответствует текущему содержанию страницы. Тут, например, было бы правильно использовать http://127.0.0.1:5500/index.html?p=2.

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

Для этого нам в history доступны 2 метода: pushState() и replaceState.

Метод pushState() добавляет в историю новый переход. Более детально, он делает страницу, которая была текущей до вызова pushState(), предыдущей. То есть к ней теперь мы можем перейти с помощью кнопки «Назад». А текущей теперь становится та, которую мы добавили в историю с помощью pushState(). При этом нужно понимать, что посредством pushState() мы по факту устанавливаем только URL и некоторые записи для неё в истории. Браузер не выполнять переход на этому URL, для обновления контента на странице в этом случае следует использовать JavaScript.

Синтакис:

JavaScript
history.pushState(state, unused)
history.pushState(state, unused, url)

Данный метод имеет 3 параметра:

  • state – некоторые данные в формате объекта, которые необходимо связать с создаваемой записью в истории;
  • unused – не используется и присутствует в методе по историческим причинам, в качестве значения ему можно просто передать пустую строку;
  • url (необязательно) – URL-адрес новой записи истории (если не указать, то будет использоваться текущий адрес).

Например:

JavaScript
history.pushState({id: 19456622}, '', '/1.html?id=19456622')
// в этом случае в качестве URL будет использоваться текущий адрес документа
history.pushState({id: 19456622}, '')

Получить объект истории можно с помощью свойства state:

history.state // {id: 19456622}

URL-адрес не обязательно указывать абсолютным. Если задать относительный адрес, то он разрешится относительно текущего URL. Например, если текущий адрес http://127.0.0.1/catalog/, то после history.pushState({}, '', '19456622') URL будет http://127.0.0.1/catalog/19456622.

Новый URL-адрес должен иметь то же origin, что и текущий URL-адрес. Если мы захотим выполнить history.pushState({}, '', 'https://www.google.com/') для страницы, которое имеет другое происхождение, то будет вызвано исключение:

Произошло исключение при вызове history.pushState(), так как новый URL имеет другой origin

Метод replaceState() в отличие от pushState() просто изменяет текущий элемент истории.

Назначение объекта history

Объект history отвечает за историю переходов, которые пользователь совершил в переделах одного окна или вкладки браузера. Эти переходы браузер сохраняет в сессию истории текущего окна (вкладки) и пользователь с помощи кнопки "Назад" всегда может вернуться на предыдущие страницы. Кроме кнопки "Назад" пользователю доступна ещё кнопка "Вперёд", которая предназначена для того, чтобы пользователь мог вернуться обратно на страницы, с которых он ушел с помощью кнопки "Назад". Таким образом, объект history отвечает за 2 эти кнопки, и позволять не только имитировать их нажатие, но добавлять и изменять записи в истории, перехватывать события при нажатии на эти кнопки и др.

Например: В некотором окне (вкладке) браузера пользователь изначально открыл страницу 1. Просмотрев эту страницу, пользователь нажал в ней на некоторую ссылку и перешёл на страницу 2. На второй странице пользователь снова нажал на ссылку и перешёл на страницу 3. В результате сессия истории для этого окна (вкладки) будет состоять из 3 элементов.

JavaScript - история переходов в пределах одного окна (вкладки)

На текущий момент для пользователя доступна кнопка "Назад". При нажатии на эту кнопку пользователь может вернуться на страницу 2.

JavaScript - история переходов в пределах одного окна (вкладки)

В этот момент времени для пользователя становится доступны кнопки "Назад" и "Вперёд". При нажатии на кнопку "Назад" пользователь может вернуться на страницу 1, а при нажатии на кнопку "Вперёд" - на страницу 3. Таким образом, пользователь с помощью кнопок "Назад" и "Вперёд" может перемещаться по истории внутри этого окна (вкладки).

Каждый элемент в сессии состоит из:

  • data - это некоторые данные, которые можно связать с определённым элементом истории. В основном они используются для того чтобы восстановить состояние динамической страницы при переходе к ней с помощью кнопки "Назад" или "Вперёд". Т.е. сначала Вы сохраняете состояние страницы, а точнее динамических её блоков, которые загружаются с помощью технологии AJAX, в data. А потом, когда пользователь переходит к ней с помощью кнопки "Назад" или "Вперёд", Вы можете восстановить состояние этой страницы, а точнее этих динамических блоков (т.к. одного URL не достаточно) с помощью информации, сохранённой в data.
  • title - название пункта истории. В настоящее время большинство браузеров не поддерживают возможность установления названия пункта с помощью JavaScript. Браузеры в качестве названия пункта истории используют название страницы, т.е. текст, расположенный между открывающим <titie> и закрывающим </title> тегами HTML страницы.
  • url - URL адрес страницы.

Свойства, методы и события объекта history

  • Свойство history.length - возвращает количество элементов в сессии истории текущего окна (вкладки). Другими словами, данное свойство возвращает количество переходов, которые Вы можете выполнить в пределах текущего окна как вперед, так и назад. Данное свойство доступно только для чтения.
  • Свойство history.state - позволяет получить данные (data) текущего элемента истории. Эти данные можно добавить к элементу истории с помощью методов history.pushState() и history.replaceState().
  • Метод history.go(). Он позволяет переместить пользователя на некоторое количество страниц вперёд или назад по истории. Метод history.go() имеет один обязательный параметр - это число, на которое надо переместить пользователя вверх или вниз по истории. Например, history.go(2) - осуществляет перемещения пользователя на 2 шаг назад, a history.go(-2) на 2 шага вперёд. Если в качестве параметра указать значение 0, то данный метод вызовет перезагрузку страницы. Если указать в качестве значение число, которое превышает количество шагов, которые может совершить пользователь в текущем окне, то ни чего не произойдёт.
  • Метод history.back() - осуществляет перемещение пользователя на одну страницу назад по истории, т.е. он программно 'имитирует" нажатие кнопки "Назад" в браузере. Также метод history.back() можно выполнить с помощью метода history.go(-1).
  • Метод history.forward() - осуществляет перемещение пользователя на одну страницу вперёд по истории, т.е. он программно "имитирует" нажатие кнопки "Вперёд" в браузере. Также метод history.forward() можно выполнить с помощью метода history.go(1).
  • Метод history.pushState() - позволяет добавить новую запись в сессию истории текущего окна (вкладки). Добавление записи (элемента) осуществляется в конец сессии истории. JavaScript - метод history.pushstate()
    JavaScript
    history.pushState(data,title[,url]);

    Данный метод принимает 3 параметра:

    • data (обязательный параметр) - некоторые данные, которые будут связаны с этой записью в сессии истории. Если в данных нет необходимости, то используйте в качестве параметра значение null.
    • title (обязательный параметр) - название записи в сессии истории.
    • url (необязательный параметр) - это URL записи в сессии истории. Если URL не указать, то будет использоваться текущий адрес страницы.
  • Метод history.replaceState() - позволяет изменить текущий элемент истории. JavaScript - метод history.replacestate()
    JavaScript
    history.replaceState(data,title[,url]).
    Данный метод принимает 3 параметра. Назначение параметров этого метода аналогично методу history.pushState().
  • Событие popstate. Данное событие вызывает браузер при навигации по истории. Т.е. с помощью его Вы можете обрабатывать события, происходящие в браузере, когда пользователь нажимает на кнопку "Назад" или "Вперёд", или при выполнении методов history.go(), history.back(), history.forward().
    JavaScript
    onpopstate = function(event) {
      //код обработки события popstate
      //например:
      console.log(event.state);
    }
    JavaScript
    window.addEventListener ("popstate", function (e) {
    //код обработки события popstate
    });

В качестве примера рассмотрим работу с объектом history в консоли браузера:

  1. Откроем вкладку в браузере и введём в адресной строке http://www.yandex.ru/ и нажмём Enter.
  2. В этой же вкладке в адресной строке введём http://getbootstrap.com/ и нажмём опять Enter. Если посмотреть на кнопку "Назад", то он стала активной и позволяет перейти на один шаг назад, т.е. на страницу https://www.yandex.ru/. Кроме этого можно увидеть список элементов истории, если нажать правой кнопкой мыши на кнопку "Назад".
  3. Откроем консоль (клавиша F12 в браузере, вкладка "Консоль") и поработаем с историей с помощью JavaScript:
    • Узнаем количество элементов в истории: history.length;
    • Добавим новый элемент в историю: history.pushState(null,null,"http://getbootstrap.com/css/");
    • Перезагрузим страницу с помощью объекта history: history.go(0);
    • Для примера заменим текущий элемент истории и свяжем с ним строку "Привет": history.replaceState("Привет",null,"http://getbootstrap.com/javascript/");
    • Получим данные связанные с этим элементом истории: history.state;
    • Перейдём на 2 шага назад по истории, т.е. на страницу http://www.yandex.ru/: history.go(-2);
JavaScript - работа с объектом history в консоли браузера

Комментарии: 11

Денис
Денис

Спасибо за хороший разбор, понятно и просто объясняете. Только не понял, почему при history.pushState в скрипте первой страницы в браузере меняется адрес на этот новый (хотя содержание страницы остается первой страницы)

Александр Мальцев
Александр Мальцев

Спасибо! Методы history.pushState и history.replaceState изменяют URL и другие данные истории, но они не изменяют содержимое страницы и не осуществляют переход по этому URL. Изменять контент в этом случае нужно самостоятельно с помощью JavaScript.

По большому счёту эти методы и нужны в основном для AJAX-сайтов, а URL изменяем для того, чтобы при перезагрузке страницы или при переходе по этой ссылке пользователь увидел тот же контент, который видит сейчас.

Денис
Денис

понял, то есть используются для AJAX-сайтов сайтов, спасибо!

Александр Мальцев
Александр Мальцев

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

Кайли
Кайли
У вас тут явная не состыковка:
В одном месте написано:
«Например, history.go(2) — осуществляет перемещения пользователя на 2 шаг назад, a history.go(-2) на 2 шага вперёд.»
А в другом
«Также метод history.back() можно выполнить с помощью метода history.go(-1)»
«Также метод history.forward() можно выполнить с помощью метода history.go(1)»

И не понятно куда же перемещает значение с минусом — назад или вперед? Пойду выяснять практическим путём.
Артем
Артем
Уже весь Google перелопатил, как мне сделать, при клике на кнопку назад в браузере, штоб редиректило на любой сайт?
Александр Мальцев
Александр Мальцев
Такое поведение как вы описали выполнить нельзя. Добавление в историю элементов с помощью JavaScript и их изменение в настоящий момент необходимо выполнять в соответствии с правилом ограничения домена (Same Origin Policy). Т.е. в историю вы не можете добавить ресурс URL которого не совпадает с вашим доменом.
Лева
Лева
Не понимаю одно почему когда я нажимаю кнопку Назад все js коды, а именно которые приходили ajaxом исчезают?
Остаются html + css, а js нет.

Использовал getScript но к сожалению при нажатии назад уже загружается весь сайт, как исправить?
Как сделать так чтобы при нажатии на кнопку назад страница высодилась моментально со всеми предыдущими ajax запросами
Александр Мальцев
Александр Мальцев
Потому что js код отрабатывает заново. Чтобы у вас страница загружалась с предыдущими настройками (в том же состоянии) все параметры необходимо вынести в GET и передавать их в составе URL-запроса. В этом случае у вас не будет этих проблем.
Лева
Лева
Вы имеете ввиду совершать ajax запрос параметром GET?
Просто страницы у меня передаются в GET параметрами допустим index.php?id=5, а запросы на сервер POST параметрами.
Александр Мальцев
Александр Мальцев
Да, в этом случае при переходе у вас все настройки будут храниться в составе URL, и следовательно пользователь увидит туже страницу, которая у него была.
Если вы используете POST, то тогда вам нужно сохранять настройки страницы в какое-нибудь другое место. Например, в cookies или local storage. А затем использовать их для восстановления вида страницы, которую пользователю она была предоставлена до этого.