摘要:在本教程中,您将学习如何使用 JavaScript 历史 pushState()
方法。
JavaScript 历史 pushState() 方法介绍
history.pushState()
方法允许您向 Web 浏览器的会话历史堆栈 添加一个条目。
以下是 pushState()
方法的语法
history.pushState(state, title, [,url])
Code language: CSS (css)
pushState()
方法接受三个参数
1) state
state
是一个可序列化对象。当您导航到一个新状态时,会触发一个 popstate
事件。而 popstate
事件有一个 state
属性,它引用历史条目的 state
对象。
2) title
大多数浏览器目前忽略此 title 属性。如果您想更改文档的标题,可以使用 documen.title
属性。
在实践中,您将一个空字符串传递给 title
参数。
3) url
可选的 url
允许您定义新历史条目的 URL。该 URL 必须与当前 URL 的来源相同,否则该方法将抛出异常。
当您设置新的 url
时,Web 浏览器不会加载 url
。如果您没有指定 url
,它将默认为当前 URL。
JavaScript 历史 pushState() 示例
我们将制作一个简单的应用程序,它显示三个选项卡:React、Vue 和 Angular。
当您单击一个选项卡时,它将显示所选选项卡的内容。它还将使用 history.pushState()
方法更新 URL。
如果您复制带有井号的 URL 并从 Web 浏览器加载它,该应用程序将加载与该 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>
Code language: HTML, XML (xml)
您可以在此处找到 style.css
文件。
在 app.js
文件中
首先,使用 querySelector()
方法选择选项卡和内容元素。
const tabs = document.querySelector(".tabs");
const content = document.querySelector(".tabs > .content");
Code language: JavaScript (javascript)
其次,定义一个 map 对象,将 URL 井号与每个选项卡 ID 关联起来。
const hashes = new Map([
["#react", "tab1"],
["#vue", "tab2"],
["#angular", "tab3"],
]);
Code language: JavaScript (javascript)
第三,定义另一个名为 data 的 map,用于将选项卡 ID 与一个对象进行映射。该对象具有两个属性: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.",
},
],
]);
Code language: JavaScript (javascript)
第四,当每个选项卡(或 li 元素)被单击时,click
事件将发生。为了提高效率,我们将使用 事件委托。
因此,我们不会处理每个选项卡上的 click
事件,而是处理每个选项卡父元素上的 click
事件。
tabs.addEventListener("click", function (event) {
if (!event.target.id) return;
update(event.target.id);
});
Code language: JavaScript (javascript)
if
语句确保事件处理程序仅在 click
事件发生在每个单独的选项卡上时才更新内容和 url。当您单击选项卡的内容区域时,它不会执行任何操作。
在事件处理程序中,我们调用 update()
函数并将选项卡 ID 传递给它。
第五,以下定义了 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;
}
};
Code language: JavaScript (javascript)
update()
函数从当前选项卡中删除 .active
类,并将相同的 CSS 类设置为当前选定的选项卡。
它还根据选项卡 ID 从数据中获取 url 和内容。为了更新 URL,它使用 history.pushState()
方法。
该应用程序应该按预期工作,只有一个问题。
如果您复制 URL
https://tutorial.javascript.ac.cn/sample/webapis/history/index.html#angular
Code language: JavaScript (javascript)
… 并将其粘贴到新的浏览器窗口中,该应用程序将显示 React
选项卡而不是 Angular
选项卡。
为了解决这个问题,我们使用 location
对象从 URL 中获取井号,并在页面加载时调用 update()
函数。
(() => {
// get tab id from the hash
const tabId = hashes.get(window.location.hash);
// update the tab
if (tabId) update(tabId);
})();
Code language: JavaScript (javascript)
以下显示了完整的 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);
})();
Code language: JavaScript (javascript)
总结
- 使用
history.pushState()
方法向 Web 浏览器的会话历史堆栈添加一个条目。