В этом руководстве вы узнаете, как использовать метод 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);
})();