入口
万变不离其宗,看源码先找入口,首先看vue-router
的入口,定义在src/index
中。
vue-router
是基于类(class)实现。- 类中提供了构造方法和一些其他方法,类定义完后给类添加了
install
方法。 vue-router
其实是一个vue插件,使用vue-router
需要Vue.use(vue-router)
。Vue.use
原理可看另一篇文章,总结一句话就是:Vue会调用插件的install
函数或者插件本身。
install
// src/install
import View from './components/view'
import Link from './components/link'
export let _Vue
export function install (Vue) {
// 判断vue-router是否已经安装
if (install.installed && _Vue === Vue) return
install.installed = true
_Vue = Vue
const isDef = v => v !== undefined
const registerInstance = (vm, callVal) => {
let i = vm.$options._parentVnode
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
i(vm, callVal)
}
}
// 混合beforeCreate、destroyed
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
// 在Vue原型上添加$router、$route
Object.defineProperty(Vue.prototype, '$router', {
get () {
return this._routerRoot._router }
})
Object.defineProperty(Vue.prototype, '$route', {
get () {
return this._routerRoot._route }
})
// 注册全局组件
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}
- 首先在
install
里判断插件是否已经被安装,没有则添加install
标识。 - 在
destroyed
和beforeCreate
中混合自己的方法,执行init
方法。 - 在Vue原型上添加
$router
和$route
属性 - 注册全局组件
RouterView
和RouterLink
实例化Vue-Router
// src/index
constructor (options: RouterOptions = {
}) {
// 根实例
this.app = null
// 所有组件实例
this.apps = []
this.options = options
this.beforeHooks = []
this.resolveHooks = []
this.afterHooks = []
// 创建路由映射
this.matcher = createMatcher(options.routes || [], this)
// 配置mode
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
// 根据mode来实例化各自的History
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}`)
}
}
}
在Vue.use(vue-router)
后,通常我们将实例化Vue-Router
。在类的构造方法中,设置