这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战
VueRouter 对象
VueRouter 的实现是一个类,我们先对它做一个简单地分析,它的定义在 src/index.js
中。 VueRouter
定义了一些属性和方法,我们先从它的构造函数看,当我们执行 new VueRouter
的时候做了哪些事情。
constructor (options: RouterOptions = {}) {
this.app = null
this.apps = []
this.options = options
this.beforeHooks = []
this.resolveHooks = []
this.afterHooks = []
this.matcher = createMatcher(options.routes || [], this)
let mode = options.mode || 'hash'
this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract'
}
this.mode = mode
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}`)
}
}
}
复制代码
构造函数定义了一些属性,其中 this.app
表示根 Vue
实例,this.apps
保存持有 $options.router
属性的 Vue
实例,this.options
保存传入的路由配置,this.beforeHooks
、 this.resolveHooks
、this.afterHooks
表示一些钩子函数,我们之后会介绍,this.matcher
表示路由匹配器,我们之后会介绍,this.fallback
表示在浏览器不支持 history.pushState
的情况下,根据传入的 fallback
配置参数,决定是否回退到hash模式,this.mode
表示路由创建的模式,this.history
表示路由历史的具体的实现实例,它是根据 this.mode
的不同实现不同,它有 History
基类,然后不同的 history
实现都是继承 History
。
实例化 VueRouter
后会返回它的实例 router
,我们在 new Vue
的时候会把 router
作为配置的属性传入,回顾一下上一节我们讲 beforeCreate
混入的时候有这么一段代码:
beforeCreate() {
if (isDef(this.$options.router)) {
// ...
this._router = this.$options.router
this._router.init(this)
// ...
}
}
复制代码
所以组件在执行 beforeCreate
钩子函数的时候,如果传入了 router
实例,都会执行 router.init
方法。 init
的逻辑很简单,它传入的参数是 Vue
实例,然后存储到 this.apps
中;只有根 Vue
实例会保存到 this.app
中,并且会拿到当前的 this.history
,根据它的不同类型来执行不同逻辑,由于我们平时使用 hash
路由多一些,所以我们先看这部分逻辑,先定义了 setupHashListener
函数,接着执行了 history.transitionTo
方法,它是定义在 History
基类中,代码在 src/history/base.js
:
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const route = this.router.match(location, this.current)
// ...
}
复制代码
实际上是调用了 this.matcher.match
方法去做匹配。
总结
在组件的初始化阶段,执行到 beforeCreate
钩子函数的时候会执行 router.init
方法,然后又会执行 history.transitionTo
方法做路由过渡,进而引出了 matcher
的概念.