在之前的文章([标记本次浏览的第一个页面](标记本次浏览的第一个页面 (juejin.cn)))中提到vue-router会在history.state中存放一个字符串来标识路由,这一点在文档中没有明说它的原理,我们在利用history.state来标记第一层路由的时候需要对vue-router的这一数据进行特殊的处理。
vue-router@4
但是在新的vue-router@4中,我们不需要对history.state进行特殊的处理,反而可以利用vue-router存放在其中的数据来标记第一层路由。
在vue-router@4的文档中有这样一段描述(history.state的用法)
Vue Router 将信息保存在 history.state 上。如果你有任何手动调用 history.pushState() 的代码,你应该避免它,或者用的 router.push() 和 history.replaceState() 进行重构。原因:我们使用历史状态来保存导航信息,如滚动位置,以前的地址等。
也就是是说vue-router@4明确的说明了,路由信息是保存在history.state中的。
history.state
我们用vue-cli创建一个vue@3的项目来看一个例子,如果我们直接打开网址(比如从VSCode的控制台按Ctrl进入http://localhost:8080),在浏览器的控制台打印`history.state`,可以看到输出为:
{
back: null
current: "/"
forward: null
position: 0
replaced: true
scroll: null
}
这些就是vue-router存放的路由信息,其中:
- back:上一层路由地址
- current:当前路由地址
- forward:下一层路由地址
- position:当前路由在历史记录中的位置
- replaced:是否是替换路由
- scroll:页面位置信息
在源码中其类型被定义为:
interface StateEntry extends HistoryState {
back: HistoryLocation | null
current: HistoryLocation
forward: HistoryLocation | null
position: number
replaced: boolean
scroll: _ScrollPositionNormalized | null | false
}
且我们可以看到它是这样被初始化的:
{
back: null,
current: currentLocation.value,
forward: null,
// the length is off by one, we need to decrease it
position: history.length - 1,
replaced: true,
// don't add a scroll as the user may have an anchor and we want
// scrollBehavior to be triggered without a saved position
scroll: null,
}
也就是说position是当前路由历史长度减一,如果这是浏览器打开的第一个页面,路由历史长度为1,那么当前路由位置就是0。以此我们可以判断这是进入页面的第一层路由。
当position不为0的时候,比如先打开浏览器,在输入http://localhost:8080时,由于浏览器初始页面也算是一层路由,`position`就为1。
{
back: null
current: "/"
forward: "/about"
position: 1
replaced: true
scroll: {left: 0, top: 0}
}
此时我们可以通过判断back是否为null来判断是否是第一层路由。因为vue-router随他可以取得浏览器历史的位置,但无法获取其他页面的路径。而在自身的路由体系内,路径都是可以拿到的。因为,back === null就以为这当前处于这个SPA的第一层路由。
总结
在vue-router@4中,我们可以通过:
window.history.state.position === 0 || window.history.state.back === null
来判断当前路由是否是本次SPA浏览的第一层路由。