Chrome 105 在 Navigation API(在 102 版中引入)的 NavigateEvent
上引入了两个新方法,以改进在实践中已证明存在问题的方法。intercept()
取代了难以使用的 transitionWhile()
,可让开发者控制导航后的状态。scroll()
方法会滚动到网址中指定的锚点,它取代了 restoreScroll()
,后者不适用于所有类型的导航。
在本文中,我将介绍这两种方法存在的问题,以及新方法如何解决这些问题。
NavigateEvent.transitionWhile()
NavigateEvent.trasitionWhile()
方法是在 Chrome 102 中随 Navigation API 一起引入的,用于拦截单页应用中客户端转换的导航。其第一个参数是一个 Promise,用于向浏览器和 Web 应用的其他部分发出完成信号。
但在实践中,这种方法效果不佳。请考虑以下常见编码模式:
event.transitionWhile((async () => {
doSyncStuff();
await doAsyncStuff();
})());
这在功能上等效于以下代码。这会导致在 API 意识到开发者打算拦截导航之前,导航的某些部分会运行。
doSyncStuff();
event.transitionWhile((async () => {
await doAsyncStuff();
})());
这可能会导致应用出现问题的一个示例是,滚动恢复逻辑会在 DOM 更改后(而不是之前)捕获滚动位置。
具体变化
为了替换 transitionWhile()
,当前规范引入了 NavigateEvent.intercept()
。除了 transitionWhile()
支持的 focusReset
和 scrollRestoration
属性之外,新方法还接受一个处理程序。新处理脚本始终在导航提交后运行,并且已捕获滚动位置等内容,从而避免了 transitionWhile()
出现的问题。
transitionWhile()
方法仍然可用,但已被弃用,并将在 Chrome 108 中移除。
使用 intercept()
NavigateEvent.intercept()
受到与 transitionWhile()
相同的限制,即无法对所有导航事件进行调用。无法拦截跨源导航,也无法跨文档遍历。这样做会抛出 "SecurityError"
类型的 DOMException
。
如需使用 intercept()
,只需在调用它时传递自定义处理程序即可。
navigation.addEventListener("navigate", event => {
event.intercept({
async handler() {
doSyncStuff();
await doAsyncStuff();
}
});
});
NavigateEvent.scroll()
导航(例如从页面顶部到锚点的导航,称为从 /a
移至 /a#id
)完全由浏览器处理,即使在单页应用中也是如此。但是,导航到另一个“页面”上的锚点(/a
到 /b#id
)对于多页应用来说很简单,但对于单页应用来说则更复杂。应用必须使用 NavigateEvent.transitionWhile()
拦截导航到 /b#id
的操作,然后调用 NavigateEvent.restoreScroll()
以将锚点显示在视图中。如上所述,目前很难做到这一点。
具体变化
在单页应用中,您现在可以控制是浏览器处理滚动到锚点,还是您的代码处理滚动到锚点。
使用 scroll()
默认情况下,拦截处理脚本执行完毕后,浏览器会尝试自动处理滚动。如果您想自行处理滚动,请将 scroll
设置为 "manual"
,然后在浏览器应尝试设置滚动位置时调用 NavigateEvent.scroll()
。
navigation.addEventListener("manual", event => {
scroll: "manual",
event.intercept({
async handler() {
doSyncStuff();
// Handle scrolling earlier than by default:
event.scroll();
await doAsyncStuff();
}
});
});
restoreScroll()
方法仍然可用,但已被弃用,并将在 Chrome 108 中移除。
总结
我们希望尽快更新有关 Navigation API 的文章。与此同时,此 API 的规范包含专门面向 Web 开发者的大量信息。