vue-router 原理

462 阅读3分钟

Vue-router原理了解一下:

.vue-router的核心原理就是,更新视图但不重新请求数据。

vue中router组件中运用代码如下:

import Vue from 'vue'
import Router from 'vue-router'
import routes from './routes'

Vue.use(Router)

export default new Router({
  // mode: 'history',
  routes
})

vue-router 实现单页面跳转,提供了两种方式:hash模式,history模式,更新视图但不重新请求页面是前端路由原理的核心之一,目前在浏览器中这一切的实现主要有两种方式:

1.hash ------ 利用RUL中的hash("#")

http://localhost:8080/#/recommend

2.history ------- 利用History interface在HTML5中新增的方法。

http://localhost:8080/recommend

如何选择vue-router模式

在vue-router中,它提供了mode参数来决定采用哪一种方式,选择流程如下:

参数mode:

  • 默认模式:hash

  • history 注:如果浏览器不支持history新特性,则采用hash方式

  • history对应的是HTML5History对象,hash对应的是HashHistory对象,abstract对应的是AbstractHistory对象。在初始化对应的history之前,会对mode做一些校验:若浏览器不支持HTML5History方式(通过supportsPushState遍历判断),则mode设为hash,若不是在浏览器环境下运行,则mode设为abstract

switch (mode) {
  case 'history':
    this.history = new HTML5History(this, options.base)
    break
  case 'hash':
    this.history = new HashHistory(this, options.base, this.fallback)
    break
  case 'abstract':
    this.history = new AbstractHistory(this, options.base)
    break
  default:
    if (process.env.NODE_ENV !== 'production') {
      assert(false, `invalid mode: ${mode}`)
    }
}

HashHistory

HashHistory替换路由可以通过不同方式,一个是push,一个是replace。

HashHistory.push() 和 HashHistory.replace()

从设置路由改变到视图更新的流程:

$router.push() --> HashHistory.push() --> History.transitionTo() --> History.updateRoute() --> {app._route = route} --> vm.render()

解析流程:

1 $router.push() //调用方法

2 HashHistory.push() //根据hash模式调用,设置hash并添加到浏览器历史记录(添加到栈顶)(window.location.hash= XXX)

3 History.transitionTo() //监测更新,更新则调用History.updateRoute()

4 History.updateRoute() //更新路由

5 {app._route= route} //替换当前app路由

6 vm.render() //更新视图

HashHistory.replace()

replace()方法与push()方法不同之处在于,它并不是将新路由添加到浏览器访问历史的栈顶,而是替换掉当前的路由

replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
 this.transitionTo(location, route => {
   replaceHash(route.fullPath)
   onComplete && onComplete(route)
 }, onAbort)
}
 
function replaceHash (path) {
 const i = window.location.href.indexOf('#')
 window.location.replace(
   window.location.href.slice(0, i >= 0 ? i : 0) + '#' + path
 )
}

HTML5History

History interface是浏览器历史记录栈提供的接口,通过back(),forward(),go()等方法,我们可以读取浏览器历史记录栈的信息,进行各种跳转操作。

从HTML5开始,History interface有进一步修炼:pushState(), replaceState() 这下不仅是读取了,还可以对浏览器历史记录栈进行修改:

window.history.pushState(stateObject, title, URL)window.history.replaceState(stateObject, title,URL)
  • stateObject: 当浏览器跳转到新的状态时,将触发popState事件,该事件将携带这个stateObject参数的副本
  • title: 所添加记录的标题
  • URL: 所添加记录的URL

1.push

与hash模式类似,只是将window.hash改为history.pushState

2.replace

与hash模式类似,只是将window.replace改为history.replaceState

3.监听地址变化

在HTML5History的构造函数中监听popState(window.onpopstate)

如何选择HashHistory和HTML5History(hash和history)

对于这个问题我推荐使用history模式,其中原因不只是hash模式的"#"符号不好看。

  • pushState设置的新URL可以是与当前URL同源的任意URL;而hash只可修改#后面的部分,故只可设置与当前同文档的URL
  • pushState通过stateObject可以添加任意类型的数据到记录中;而hash只可添加短字符串
  • pushState可额外设置title属性供后续使用
  • history模式则会将URL修改得就和正常请求后端的URL一样,如后端没有配置对应/user/id的路由处理,则会返回404错误