navigation api是W3C提出的实验性方案,2023年成为正式标准草案,chrome、edge
浏览器支持相当不错了。
提供了启动、拦截和管理浏览器导航操作的功能。它还可以检查应用程序的历史记录条目。这是对之前 Web 平台特性(例如历史记录 API 和 window.location
的继承并解决了它们的缺点,且专门针对单页应用程序(SPA)的需求。
- 拦截导航:在用户触发导航(点击链接、前进/后退)时拦截并自定义处理。
- 细粒度控制:管理导航队列、处理异步操作、动态更新页面内容。
- 增强历史管理:更灵活地操作历史记录,支持复杂状态管理。
history api处理导航的缺点
- 状态与 URL 分离: 状态(
state
对象)与 URL 改变是绑定的,但获取和监听状态变化非常笨拙(依赖popstate
事件,且该事件也响应浏览器按钮)。 - 导航监听困难: 区分用户点击链接、表单提交、脚本触发导航、浏览器前进/后退非常困难。
popstate
只响应某些导航(主要是同文档的历史切换)。 - 缺乏对"导航"过程的控制: 无法优雅地拦截导航、显示加载状态、处理取消或失败。
- 信息不完整: 难以获取导航的详细信息(如导航类型、目标 URL、发起者等)。
- 操作历史条目不便: 遍历、修改或获取历史条目的详细信息很麻烦。
- 只能导航同源路径
属性
activation
-
entry
:NavigationHistoryEntry
对象,表示当前导航页信息-
id 导航唯一标识,始终代表特定的历史记录条目。
-
index 历史条目列表(即
Navigation.entries()
返回的列表)中历史条目的索引,如果该条目未出现在列表中,则返回-1
。 -
key 表示历史条目在条目列表中的位置,而不是条目本身。在整个会话历史中不变。 可用于
traverseTo()
导航到指定条目。 -
sameDocument 判断此历史记录条目与当前
Document
值属于同一个document
。例如hash导航 -
url 此历史记录条目的绝对 URL 地址。
-
getState()
获取编程式导航传递的state数据。这是替代传统history.state
的更易访问的方式。
jsasync function handleReload() { // 通过 reload() 更新现有状态 await navigation.reload({ state: { ...navigation.currentEntry.getState(), newState: 3 }, }); // 将当前状态打印到控制台 const current = navigation.currentEntry; console.log(current.getState()); }
dispose
事件在条目不再是历史记录条目列表的一部分时触发。
-

from
:NavigationHistoryEntry
对象,原导航页信息。内部属性同上,如果导航到非同源页面将返回null。

navigationType
: 表示导航类型的字符串。push
:导航到新位置,导致新条目被推送到历史列表中。reload
:Navigation.currentEntry
已重新加载。调用reload
。replace
:Navigation.currentEntry
被替换为新的历史记录条目。此新条目将重用相同的key
,但分配不同的id
。traverse
:浏览器从一个现有的历史记录条目导航到另一个现有的历史记录条目。通过traverseTo, back. forward
导航。
canGoBack
是否可以在导航历史记录中向后导航,即 currentEntry
不是历史记录条目列表中的第一个。
canGoForward
是否可以在导航历史记录中向前导航,即 currentEntry
不是历史记录条目列表中的最后一个。
currentEntry
表示用户当前导航到的历史记录。即activation.entry
。
transition
表示正在进行的导航的状态,可用于跟踪正在进行的导航。如果当前没有正在进行的导航,则为 null
。
方法
back(options)
在导航历史记录中向后导航一个条目。如果当前导航在历史记录的第一个位置将会抛出错误。在调用前可以通过navigation.canGoBack
进行判断是否可以导航。
options.info
导航传递的数据,可以在navigate
事件的事件对象中获取到。可以是任何数据类型。
返回值
-
committed
当可见 URL 发生改变并且新的NavigationHistoryEntry
被创建时,将兑现的Promise
。 -
finished
当intercept()
处理器返回的所有 promise 都被兑现时,将兑现的Promise
。这相当于当navigatesuccess
事件触发时,兑现NavigationTransition.finished
promise。
forward(options)
在导航历史记录中向前导航一个条目。参数和返回值介绍同上。如果当前导航在历史记录的最后一个位置将会抛出错误。在调用前可以通过navigation.canGoForward
进行判断是否可以导航。
entries()
返回一个 NavigationHistoryEntry
对象数组,代表所有现有的历史导航记录条目。注意他只能获取和当前文档同源的历史条目。history.length
会返回当前tab页面所有历史条目总和(不管同不同源)

navigate(url, options)
导航到特定的 URL,更新历史记录条目列表中提供的任何状态。
url
要导航到的目标的 URL。options.state
将在导航完成后存储在关联的NavigationHistoryEntry
中,可通过getState()
检索。存储在state
中的任何数据都必须是可结构化克隆的。options.info
导航传递的数据,可以在navigate
事件的事件对象中获取到。可以是任何数据类型。options.history
设置此导航的历史记录行为的枚举值。可用的值包括:auto
:默认值;通常会执行push
导航,但在特殊情况下会执行replace
导航。push
:将会把新的NavigationHistoryEntry
推送到历史记录条目列表中。replace
:将替换当前的NavigationHistoryEntry
。
返回值
-
committed
当可见 URL 发生改变并且新的NavigationHistoryEntry
被创建时,将兑现的Promise
。 -
finished
当intercept()
处理器返回的所有 promise 都被兑现时,将兑现的Promise
。这相当于当navigatesuccess
事件触发时,兑现NavigationTransition.finished
promise。
reload(options)
重新加载当前 URL,同时更新历史记录条目列表中对应的条目的状态。
options.state
将在导航完成后存储在关联的NavigationHistoryEntry
中,可通过getState()
检索。存储在state
中的任何数据都必须是可结构化克隆的。options.info
导航传递的数据,可以在navigate
事件的事件对象中获取到。可以是任何数据类型。
traverseTo(key, options)
导航到由给定的 key
标识的 NavigationHistoryEntry
。
key
要导航到的目标的NavigationHistoryEntry.key
。options.info
导航传递的数据,可以在navigate
事件的事件对象中获取到。可以是任何数据类型。
返回值
-
committed
当可见 URL 发生改变并且新的NavigationHistoryEntry
被创建时,将兑现的Promise
。 -
finished
当intercept()
处理器返回的所有 promise 都被兑现时,将兑现的Promise
。这相当于当navigatesuccess
事件触发时,兑现NavigationTransition.finished
promise。
updateCurrentEntry(options)
更新 currentEntry
的 state
;用于状态改变且与导航或重新加载无关的情况。类似于 history.replaceState
。
options.state
将在导航完成后存储在关联的NavigationHistoryEntry
中,可通过getState()
检索。存储在state
中的任何数据都必须是可结构化克隆的。
js
navigation.updateCurrentEntry({state:{name:'zh', age: 25}})
navigation.currentEntry.getState()

事件
currententrychange
在 Navigation.currentEntry
发生更改时触发。即可见 URL 已更改且 NavigationHistoryEntry
已更新(state或其他数据更新)。
- 同文档导航(例如
back(), forward(), traverseTo()
)。 - 替换(即
navigate()
调用,并将history
参数设置为replace
)。 - 更改条目状态的其他调用(例如
updateCurrentEntry()
,或 History API的History.replaceState()
)。
可以在事件对象NavigationCurrentEntryChangeEvent
中获取
from
导航来源的NavigationHistoryEntry
。navigationType
导致改变的导航的类型。
navigate
在发起任何类型的导航时触发,让你可以根据需要进行拦截。
js
navigation.addEventListener('navigate', (event) => {
// 检查是否可拦截(同源导航)
if (!event.canIntercept) return;
// 阻止默认刷新行为,也可阻止navigation.reload()
// event.preventDefault();
// 拦截导航过程
event.intercept({
handler: async () => {
// 这里执行无刷新更新
}
});
});
该事件的事件对象NavigateEvent
中提供了很多的属性和方法供我们对导航进行处理。
canIntercept
是否可以拦截导航(一般同源导航可以被拦截 )并重写其 URL。 何时可以进行拦截请看这里destination
返回一个NavigationDestination
对象,表示要导航到的目标。downloadRequest
在导航为下载导航的情况下返回请求下载的文件的文件名。例如具有 download 属性的<a> 或 <area>
元素。formData
在导航为POST
表单提交导航的情况下返回表示提交的数据的FormData
对象,否则返回null
。hashChange
当前导航是否是修改hash的导航。hasUAVisualTransition
在用户代理分派此事件之前已为此导航执行了可视化的过渡时返回true
,否则返回false
。info
返回启动导航操作传递的info
数据值,如果没有传递info
数据,则返回undefined
。navigationType
返回导航的类型(push
、reload
、replace
或traverse
)。push
:导航到新位置,导致新条目被推送到历史列表中。reload
:Navigation.currentEntry
已重新加载。replace
:Navigation.currentEntry
被替换为新的历史记录条目。此新条目将重用相同的key
,但分配不同的id
。traverse
:浏览器从一个现有的历史记录条目导航到另一个现有的历史记录条目。
signal
返回一个AbortSignal
,如果导航被取消(例如,用户按下浏览器的"停止"按钮,或者另一个导航启动并因此取消正在进行的导航),该信号将被中止。可以在导航取消时阻止一些不必要的网络请求。userInitiated
导航是否是由用户发起的(例如,通过单击链接、提交表单或按浏览器的"后退"/"前进"按钮)。sourceElement
返回触发元素(a, area, input["submit"], button["submit"], form
)。intercept(options)
方法拦截此导航,将其转变为到目标 URL 的同一文档导航。options.handler
定义导航处理行为的回调函数。这通常用于处理资源获取并返回 promise。focusReset
定义导航的焦点行为。这可能接受以下值之一:after-transition
一旦处理器返回的 promise 兑现,浏览器将聚焦具有autofocus
属性的第一个元素,或者如果没有元素设置autofocus
,则聚焦<body>
元素。这是默认值。manual
禁用默认行为。
scroll
定义导航的滚动行为。这可能接受以下值之一:after-transition
允许浏览器处理滚动,例如,如果 URL 包含片段,则滚动到相关片段标识符;如果重新加载页面或重新访问历史记录中的页面,则将滚动位置恢复到上次的同一位置。这是默认值。manual
禁用默认行为。
scroll()
方法可用于手动触发浏览器在导航过程中执行的滚动行为,如果希望该行为在导航处理完成之前发生,则可以调用此方法。
navigateerror
在导航失败后触发。
- 导航时出现错误
- 调用导航api传递参数错误
- 网络请求失败
- 用户主动中止
js
// 拦截处理抛出错误
navigation.addEventListener('navigate', (event) => {
event.intercept({
handler: () => {
throw new Error('权限校验失败'); // 触发 navigateerror
}
});
});
// 网络请求失败
navigation.navigate('/unreachable-page');
// 用户主动中止
const controller = new AbortController();
navigation.navigate('/cancelable', {
signal: controller.signal
});
controller.abort(); // 触发 AbortError
navigatesuccess
在导航成功完成后触发。
- 导航完成
- 拦截处理函数完成 (intercept)
- 目标资源加载完成
应用
替代history api, hash
模式实现前端路由。
js
<a href="/zh">zh</a>
<a href="/llm">llm</a>
<div id="container">我是默认页面</div>
<script>
const container = document.getElementById("container");
const aEls = document.getElementsByTagName("a");
const changeContent = (event) => {
console.log("event", event)
if (!event.canIntercept) return;
event.intercept({
async handler () {
switch (location.pathname) {
case "/zh":
container.innerHTML = "我是zh页面"
break;
case "/llm":
container.innerHTML = "我是llm页面"
break;
default:
container.innerHTML = "我是其他页面"
break;
}
},
});
}
navigation.addEventListener("navigate", changeContent)
</script>
兼容性

参考
## 往期年度总结
- 在上海的忙碌一年,依旧充满憧憬(2024)
- 四年沿海城市,刚毕业,一年3家公司
- 七月仿佛又回到了那一年(2023年中总结)
- 一位初入职场前端仔的年度终结 <回顾2022,展望2023>
- 大学两年半的前端学习
往期文章
- 告别后端,浏览器端也可以轻松操作文件了?
- 文本选区有啥魔力
- 前端可以知道的录制浏览器标签页,没有黑魔法
- 一个关联本地页面镜像的功能,我了解到这些
- 啊,原来sessionStorage是这样的
- 如何像掘金编辑器一样粘贴图片即可上传服务器
- Nest装饰器全解析
- Nest世界中的AOP
- Nestjs如何解析http传输的数据
- 如何理解js的DOM事件系统
- 半年没看vue官网,3.5刚刚发布,趁机整理下
- 啊,你还在找一款强大的表格组件吗?
- 前端大量数据层级展示及搜索定位预览
- 如何从0开始认识m3u8(提取,解析及下载)
- 展示大量数据节点(tree),引发的一次性能排查
- ts装饰器的那点东西
- 这是你所知道的ts类型断言和类型守卫吗?
- TypeScript官网内容解读
- 经常使用ts的你,知道这些内容?
- 你有了解过原生css的scope?
- 现在比较常用的移动端调试你知道哪些?
- 众多跨标签页通信方式,你知道哪些?(二)
- 众多跨标签页通信方式,你知道哪些?
- 反调试吗?如何监听devtools的打开与关闭
- 因为原生,选择一家公司(前端如何防笔试作弊)
- 结合开发,带你熟悉package.json与tsconfig.json配置
- 如何优雅的在项目中使用echarts
- 如何优雅的做项目国际化
- 近三个月的排错,原来的憧憬消失喽
- 带你从0开始了解vue3核心(运行时)
- 带你从0开始了解vue3核心(computed, watch)
- 带你从0开始了解vue3核心(响应式)
- 3w+字的后台管理通用功能解决方案送给你
- 入职之前,狂补技术,4w字的前端技术解决方案送给你(vue3 + vite )
专栏文章
🔥如果此文对你有帮助的话,欢迎💗关注 、👍点赞 、⭐收藏 、✍️评论, 支持一下博主~
公众号:全栈追逐者,不定期的更新内容,关注不错过哦!