# 插件源码分析
# 背景
在使用vue-router时,有一个步骤:
import VueRouter from 'vue-router'
import Vue from 'vue'
Vue.use(VueRouter)
Vue.use是Vue开放出得一个接口用于调用插件,use方法会调用插件的install方法,并传入Vue构造函数。
# VueRouter的install方法
import View from './components/view'
import Link from './components/link'
export let _Vue
export function install (Vue) {
// 避免重复执行
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)
}
}
// 混入方法
Vue.mixin({
beforeCreate () {
// 如果$options存在router,则this必定是根实例(因为我们只在根实例的选项中添加了router)
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
// 将_route声明为响应式对象
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
// 获得根组件实例
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
// 为_router对象定义别名
Object.defineProperty(Vue.prototype, '$router', {
get () { return this._routerRoot._router }
})
// 为_route对象定义别名
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方法上添加和检查installed属性避免重复执行
- 每个组件内都会有一个_routerRoot指向根组件实例
- 每个组件的
$router和$route属性都指向根组件实例的_router和_route - 如果我们想要在组件实例上挂载一些属性和方法,可以通过mixin和钩子函数来实现
- 插件注册了全局组件RouterView和RouterLink
# registerRouteInstance
更新组件实例
← 导航守卫