В этом руководстве вы узнаете, как использовать метод JavaScript history.pushState().
Метод history.pushState()
позволяет добавить запись в стек истории сеансов веб-браузера.
Синтаксис:
history.pushState(state, title, [,url])
Метод принимает три параметра:
1) state
state
— сериализуемый объект. При переходе в новое состояние запускается событие popstate
. А событие popstate
имеет свойство state
, которое ссылается на объект state
записи истории.
2) title
Большинство браузеров в настоящее время используют это свойство title. Если вы хотите изменить заголовок документа, вы можете вместо этого использовать свойство documen.title
.
На практике вы передаете пустую строку параметру title
.
3) url
Необязательный url
позволяет вам определить URL-адрес новой записи в истории. URL-адрес должен иметь то же происхождение, что и текущий URL-адрес, иначе метод вызовет исключение.
Когда вы устанавливаете новые url
, веб-браузер не будет загружать url
. По умолчанию url
использует текущий URL-адрес, если вы его не укажете.
Пример
Мы создадим простое приложение с тремя вкладками: React, Vue и Angular.
При нажатии на вкладку отображается содержимое выбранной вкладки. он также обновится URL-адрес, используя метод history.pushState()
:
Если вы скопируете URL-адрес с хэштегом и загрузите его из веб-браузера, приложение загрузит соответствующий контент, связанный с этим URL-адресом.
Страница index.html
Следующий код определяет страницу index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JavaScript History API: pushState Demo</title>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="container">
<div class="tabs">
<ul>
<li class="active" id="tab1">React</li>
<li id="tab2">Vue</li>
<li id="tab3">Angular</li>
</ul>
<div class="content">
A JavaScript library for building user interfaces
</div>
</div>
</div>
<script src="js/app.js"></script>
</body>
</html>
В файле app.js
:
- Сначала выберите вкладки и элементы контента, используя метод
querySelector()
:
const tabs = document.querySelector(".tabs"); const content = document.querySelector(".tabs > .content");
- Во-вторых, определите объект карты, который связывает хэш URL с идентификатором каждой вкладки:
const hashes = new Map([ ["#react", "tab1"], ["#vue", "tab2"], ["#angular", "tab3"], ]);
- В-третьих, определите другую карту, называемую данными, для сопоставления идентификатора вкладки с объектом. Объект имеет два свойства:
url
иcontent
.
const data = new Map([ [ "tab1", { url: "index.html#react", content: "React is a JavaScript library for building user interfaces.", }, ], [ "tab2", { url: "index.html#vue", content: "Vue is the Progressive JavaScript Framework.", }, ], [ "tab3", { url: "index.html#angular", content: "Angular is a platform for building mobile and desktop web applications.", }, ], ]);
- В-четвертых, при нажатии каждой вкладки (или элемента li) происходит событие
click
. Чтобы сделать его более эффективным, мы будем использовать делегирование событий.
Поэтому вместо обработки события click
на каждой вкладке мы будем обрабатывать событие click
на родительском элементе каждой вкладки:
tabs.addEventListener("click", function (event) { if (!event.target.id) return; update(event.target.id); });
Оператор if
гарантирует, что обработчик событий обновит содержимое и URL-адрес только в том случае, если событие click
произойдет на каждой отдельной вкладке. Ничего не произойдет, когда вы щелкнете по области содержимого вкладки.
Внутри обработчика события мы вызываем функцию update()
и передаем ей идентификатор вкладки.
- В-пятых, следующее определяет функцию
update()
:
const update = (tabId) => { // remove the active class of the previously selected tab const currentTab = tabs.querySelector(".active"); if (currentTab.id != tabId) { currentTab.classList.remove("active"); } // add active class to the selected tab const selectedTab = document.getElementById(tabId); selectedTab.classList.add("active"); const entry = data.get(tabId); if (entry) { // update the URL history.pushState(null, "", entry.url); // change the content content.innerHTML = entry.content; } };
Функция update()
удаляет класс .active
с текущей вкладки и устанавливает тот же класс CSS для текущей выбранной вкладки.
Она также получает URL-адрес и контент из данных на основе идентификатора вкладки. Для обновления URL используется метод history.pushState()
.
Приложение должно работать должным образом только с одной проблемой.
Если вы скопируете URL-адрес:
https://www.javascripttutorial.net/sample/webapis/history/index.html#angular
… и вставьте его в новое окно браузера, приложение отобразит вкладку React
вместо вкладки Angular
.
Чтобы исправить это, мы получаем хеш из URL с помощью объекта location
и вызываем функцию update()
при загрузке страницы.
(() => { // get tab id from the hash const tabId = hashes.get(window.location.hash); // update the tab if (tabId) update(tabId); })();
Ниже показан полный файл app.js
:
const tabs = document.querySelector(".tabs"); const content = document.querySelector(".tabs > .content"); // store the relationship between hash & tab id const hashes = new Map([ ["#react", "tab1"], ["#vue", "tab2"], ["#angular", "tab3"], ]); // store the relationship between tab id and contents const data = new Map([ [ "tab1", { url: "index.html#react", content: "React is a JavaScript library for building user interfaces.", }, ], [ "tab2", { url: "index.html#vue", content: "Vue is the Progressive JavaScript Framework.", }, ], [ "tab3", { url: "index.html#angular", content: "Angular is a platform for building mobile and desktop web applications.", }, ], ]); tabs.addEventListener("click", function (event) { if (!event.target.id) return; update(event.target.id); }); const update = (tabId) => { // remove the active class of the previously selected tab const currentTab = tabs.querySelector(".active"); if (currentTab.id != tabId) { currentTab.classList.remove("active"); } // add active class to the selected tab const selectedTab = document.getElementById(tabId); selectedTab.classList.add("active"); const entry = data.get(tabId); if (entry) { // update the URL history.pushState(null, "", entry.url); // change the content content.innerHTML = entry.content; } }; (() => { // get tab id from the hash const tabId = hashes.get(window.location.hash); // update the tab if (tabId) update(tabId); })();