Window: popstate 事件
当用户浏览会话历史记录时,如果活动历史记录条目发生更改,则会触发 Window
接口的 popstate
事件。它会将当前历史记录条目更改为用户访问的最后一个页面的历史记录条目,或者如果使用 history.pushState()
将历史记录条目添加到历史记录堆栈,则使用该历史记录条目。
语法
在诸如 addEventListener()
之类的方法中使用事件名称,或设置事件处理程序属性。
addEventListener("popstate", (event) => {});
onpopstate = (event) => {};
事件类型
一个 PopStateEvent
。继承自 Event
。
事件属性
PopStateEvent.state
只读-
返回提供给
pushState()
或replaceState()
的信息的副本。
事件处理程序别名
除了 Window
接口之外,事件处理程序属性 onpopstate
也可在以下元素上使用
历史栈
如果激活的历史记录条目是由对 history.pushState()
的调用创建的,或者受对 history.replaceState()
的调用的影响,则 popstate
事件的 state
属性包含历史记录条目的状态对象的副本。
这些方法及其对应的事件可用于向历史记录堆栈添加数据,这些数据可用于重建动态生成的页面,或以其他方式更改呈现内容的状态,同时保留在同一 Document
中。
请注意,仅调用 history.pushState()
或 history.replaceState()
不会触发 popstate
事件。通过执行浏览器操作(例如单击后退或前进按钮(或在 JavaScript 中调用 history.back()
或 history.forward()
))将触发 popstate
事件。
浏览器倾向于在页面加载时以不同的方式处理 popstate
事件。Chrome(v34 之前版本)和 Safari 始终在页面加载时发出 popstate
事件,但 Firefox 不会。
注意:在编写处理 popstate
事件的函数时,务必考虑到诸如 window.location
之类的属性已反映状态更改(如果它影响了当前 URL),但 document
可能尚未反映。如果目标是捕获新文档状态已完全就位的那一刻,则应使用零延迟的 setTimeout()
方法调用,以便有效地将其内部的回调函数(执行处理)置于浏览器事件循环的末尾:window.onpopstate = () => setTimeout(doSomeThing, 0);
何时发送 popstate
首先要了解的是,为了防止不必要的弹出窗口,浏览器可能根本不会触发 popstate
事件,除非页面已与之交互。
本节介绍浏览器在可能触发 popstate
事件(即,页面已与之交互的情况)时遵循的步骤。
当导航发生时(无论是由于用户触发浏览器的 后退 按钮还是其他原因),popstate
事件都接近导航到新位置的过程的末尾。它发生在新位置加载(如果需要)、显示、可见等之后——在发送 pageshow
事件之后,但在持久用户状态信息恢复和发送 hashchange
事件之前。
为了更好地理解何时触发 popstate
事件,请考虑以下简化的事件序列,该序列在当前历史记录条目由于用户导航站点或历史记录以编程方式遍历而更改时发生。在这里,转换将当前历史记录条目更改为我们将称为 new-entry 的条目。当前页面的会话历史记录堆栈条目将称为 current-entry。
- 如果 new-entry 目前不包含现有的
Document
,则在继续之前获取内容并创建其Document
。这最终将向包含文档的Window
发送诸如DOMContentLoaded
和load
之类的事件,但以下步骤将继续执行。 - 如果 current-entry 的标题不是使用历史记录 API 方法(
pushState()
或replaceState()
)设置的,则将其条目的标题设置为其document.title
属性返回的字符串。 - 如果浏览器希望在从 current-entry 导航离开之前与其一起存储状态信息,则它会这样做。现在据说该条目具有“持久用户状态”。浏览器可能添加到历史记录会话条目中的此信息可能包括,例如,文档的滚动位置、表单输入的值以及其他此类数据。
- 如果 new-entry 的
Document
对象与 current-entry 的Document
对象不同,则会更新浏览上下文,以便其document
属性引用 new-entry 所引用的文档,并且上下文的名称会更新为与现在当前文档的上下文名称匹配。 - 重置 new-entry 的
Document
中每个表单控件的autocomplete
,其自动填充字段名称设置为off
。有关自动填充字段名称以及自动填充的工作原理的更多信息,请参阅 HTML autocomplete 属性。 - 如果 new-entry 的文档已完全加载并准备就绪——也就是说,其
readyState
为complete
——并且文档尚未可见,则将其设为可见并向文档触发pageshow
事件,其中PageTransitionEvent
的persisted
属性设置为true
。 - 文档的
URL
设置为 new-entry 的 URL。 - 如果历史记录遍历以启用替换的方式执行,则目标条目之前的条目(考虑到诸如
go()
之类方法上的delta
参数)将从历史记录堆栈中删除。 - 如果 new-entry 没有持久用户状态并且其 URL 的片段非
null
,则文档将滚动到该片段。 - 接下来,current-entry 设置为 new-entry。目标条目现在被认为是当前条目。
- 如果 new-entry 有与其一起保存的序列化状态信息,则该信息将反序列化到
History.state
;否则,state
为null
。 - 如果
state
的值发生更改,则会将popstate
事件发送到文档。 - 如果浏览器选择这样做,则会恢复任何持久用户状态。
- 如果原始条目和新条目共享相同的文档,但其 URL 中的片段不同,则会将
hashchange
事件发送到窗口。
如您所见,popstate
事件几乎是通过这种方式导航页面的过程中最后完成的操作。
示例
在 http://example.com/example.html
上运行以下代码的页面将生成如下所示的日志
window.addEventListener("popstate", (event) => {
console.log(
`location: ${document.location}, state: ${JSON.stringify(event.state)}`,
);
});
history.pushState({ page: 1 }, "title 1", "?page=1");
history.pushState({ page: 2 }, "title 2", "?page=2");
history.replaceState({ page: 3 }, "title 3", "?page=3");
history.back(); // Logs "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // Logs "location: http://example.com/example.html, state: null"
history.go(2); // Logs "location: http://example.com/example.html?page=3, state: {"page":3}"
使用 onpopstate
事件处理程序属性的相同示例
window.onpopstate = (event) => {
console.log(
`location: ${document.location}, state: ${JSON.stringify(event.state)}`,
);
};
history.pushState({ page: 1 }, "title 1", "?page=1");
history.pushState({ page: 2 }, "title 2", "?page=2");
history.replaceState({ page: 3 }, "title 3", "?page=3");
history.back(); // Logs "location: http://example.com/example.html?page=1, state: {"page":1}"
history.back(); // Logs "location: http://example.com/example.html, state: null"
history.go(2); // Logs "location: http://example.com/example.html?page=3, state: {"page":3}"
请注意,即使原始历史记录条目(对于 http://example.com/example.html
)没有与其关联的状态对象,当我们在第二次调用 history.back()
后激活该条目时,仍然会触发 popstate
事件。
规范
规范 |
---|
HTML 标准 # event-popstate |
HTML 标准 # handler-window-onpopstate |
浏览器兼容性
BCD 表格仅在浏览器中加载