VueRouter 对象
VueRouter 的实现是一个类,定义在 src/index.js 中,先看下它的构造函数
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 基类。
实例化 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 (app: any) {
process.env.NODE_ENV !== 'production' && assert(
install.installed,
`not installed. Make sure to call \`Vue.use(VueRouter)\` ` +
`before creating root instance.`
)
this.apps.push(app)
if (this.app) {
return
}
this.app = app
const history = this.history
if (history instanceof HTML5History) {
history.transitionTo(history.getCurrentLocation())
} else if (history instanceof HashHistory) {
const setupHashListener = () => {
history.setupListeners()
}
history.transitionTo(
history.getCurrentLocation(),
setupHashListener,
setupHashListener
)
}
history.listen(route => {
this.apps.forEach((app) => {
app._route = route
})
})
}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)
// ...
}它调用了路由的实例方法match,目的是找到匹配的路由。
match (
raw: RawLocation,
current?: Route,
redirectedFrom?: Location
): Route {
return this.matcher.match(raw, current, redirectedFrom)
}