JavaScript 历史 pushState

摘要:在本教程中,您将学习如何使用 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 与一个对象进行映射。该对象具有两个属性:urlcontent

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#angularCode 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 浏览器的会话历史堆栈添加一个条目。
本教程是否有帮助?