likes
comments
collection
share

探索下vue-router的hash和history模式的原理

作者站长头像
站长
· 阅读数 59

以下分析是针对vue-router 3.x版本

模式

vue-router有hash模式和history模式,这个一般都知道,但是除了这两个之外,还有一个模式叫abstract模式,适用于在node服务端,没有浏览器的history api。

不过abstract模式模式用的比较少,主要是hashhistory模式。

hash和history模式

那么它们的原理是什么?

我们通过阅读它们的源码来分析下。

vue-router项目对应目录下可以找到文件 探索下vue-router的hash和history模式的原理

hash模式

hash模式是url会有个 # 号,后面就是hash的内容,这个就叫hash模式。

hash模式会先判断当前浏览器是否支持history的pushState api,

如果支持,就直接监听popstate事件,否则有个兜底,hashchange事件。

探索下vue-router的hash和history模式的原理

针对push方法和replace方法,他也是有兜底策略

如果支持history的pushState,则直接调用history.pushState方法,否则会直接赋值hash,触发hashchange事件

同理replace方法也是,兜底会调用location.replace方法。

探索下vue-router的hash和history模式的原理

探索下vue-router的hash和history模式的原理

history模式

history模式的url就没有 # 号,这个模式需要后端支持。

它是直接监听popstate事件

探索下vue-router的hash和history模式的原理

然后push方法和replace方法是使用history.pushStatehistory.replaceState直接跳转。

探索下vue-router的hash和history模式的原理

探索下vue-router的hash和history模式的原理

history api新增

HTML5的history api新增了pushState和replaceState方法,以及hashchange事件和popstate事件。下面来讲讲它们的用法,这样就可以更好的理解上面vue-router的写法。

pushState方法

pushState方法是会新增一条历史记录,并且更新url的地址,但是不会刷新页面。你可以点击返回返回到刚才的页面。

history.pushState(state, title, url)

有三个参数

  • state 状态对象,必传,会存储在历史记录中,可以通过history.state或者popstate事件事件对象的state属性获取
  • title 字符串,标题,必传,目前浏览器都会忽略这个title,可以传''
  • url 可选,可以是相对地址和绝对地址,但是不能跨域,否则会报错。
history.pushState({name: '答案cp3'}, "title", "http://qq.com"); // VM2030:1 Uncaught DOMException: Failed to execute 'pushState' on 'History': A history state object with URL 'http://qq.com/' cannot be created in a document with origin 'https://www.baidu.com' and URL 'https://www.baidu.com/'.

history.pushState({name: '答案cp3'}, "title", "/abc");
console.log(location.href) // 'https://www.baidu.com/abc'

replaceState方法

replaceState方法是不会新增一条历史记录,而是替换当前url地址,也不会刷新页面。所以你点击返回不会返回到上一级,而是上上一级(如果存在)

参数等同pushState方法的参数,这里不再赘述。

hashchange事件

它是监听url的hash变化,只要hash有变化就会触发hashchange事件,比如赋值location.hash,location.replace等。

popstate事件

它是监听当前页面历史记录变化事件,哪些情况可以触发,比如:

  • 浏览器的返回/前进按钮
  • history.back()/history.forward()/history/go() 等方法
  • location.hash或者location.replace

要注意:调用history.pushState() 和 history.replaceState()不会触发该事件。

如果触发的时候,当前的url是调用 history.pushState() 修改或者history.replaceState() 创建的,就会在事件对象上有一个state属性,如果不是则是null

window.addEventListener('popstate',(e) => {
    console.log(e.state)
})
history.pushState({name: '答案cp3'}, "title", "?test")
history.pushState(null, null, '?test1')
history.back()

可以看到,当往url插入2条历史记录,然后调用返回键,此时url是调用history.pushState(),所以打印的了{name: '答案cp3'}

探索下vue-router的hash和history模式的原理

总结

vue-router的hash和history模式主要是使用到了history的pushState方法和replaceState方法。事件监听使用到了popstate事件。

如果不支持上面两个方法,hash模式会有兜底策略,兜底可以使用location.hash和location.replace方法代替pushState方法和replaceState方法,另外监听hashchange事件。

为什么vue-router会使用pushState方法和replaceState方法?

主要是因为它们调用不会刷新页面,这样可以保留页面的数据,体验比刷新页面会好一点。

如果还有其他答案欢迎评论交流。

本文正在参加「金石计划 . 瓜分6万现金大奖」