回顾 VueRouter 的核心代码
js
Vue.use(VueRouter)
const router = new VueRouter({
routes: [
{name: 'home', path: '/', component: Home}
]
})
new Vue ({
router,
render: h => h(App)
}).$mount("#app')
分析
Vue.use(VueRouter)
这里使用了 Vue
的插件机制,Vue.use
接收一个函数或者对象,如果是一个方法则直接调用,如果是一个对象则调用其 install
方法。install
方法接收 2 个参数,一个是 Vue
的构造函数,一个是可选的选项对象(这里不做设置)。
所以从这句话来看,我们可以将 VueRouter
看做一个有 install
静态方法的类。
且 插件是仅需要注册一次的,在 js
中,方法本身就是一个对象,那我们不妨在 install
方法上添加一个属性表明此组件是否被注册过。
在注册 VueRouter
插件的时候会传入 Vue
的构造函数,这个 Vue
在其他地方肯定还会用到,所以先将其存入到全局变量中。
js
let _Vue = null
class VueRouter {
static install (Vue) {
// 判断当前插件是否已经被安装
if (VueRouter.install.installed) return
VueRouter.install.installed = true
}
// 把 Vue 构造函数记录到全局变量中
_Vue = Vue
}
new Vue ({ router )}
创建 Vue
根实例 的时候传入 router
选项,会往所有 Vue
实例上添加 $route
和 $router
属性。
new Vue
执行的是 Vue
的构造函数,由于 VueRouter
只是一个插件,不会在 Vue
中的代码里实现添加 $router
的代码,也就是需要我们在 Vue.use(VueRouter)
注册 VueRouter
时,也就是在 install
方法里就将这部分代码写上,然后等待创建 Vue
根实例的时候再执行。
那执行的时机是什么呢?
js
// 全局注入的混入,影响注册之后所有创建的 Vue 实例
_Vue.mixin({
beforeCreate(){ ... }
})
怎么往所有 Vue
实例上添加属性呢?
js
// 往 Vue 的原型上添加 $router 属性,则以后创建出来的 Vue 实例都会包含 $router 属性
_Vue.prototype.$router = this.$options.router
这段代码写在 beforeCreate
中,this
的值指向的就是 Vue
实例,那么 this.$options.router
就可以取到传入的 router
选项。
这段代码只需要在创建 Vue
根实例 的时候执行一次,只有这个时候才会传入 router
选项,组件也是 Vue
实例,但是在创建组件的时候不必执行。
js
// 创建根实例时,往所有 Vue 实例上添加 $router 属性
_Vue.mixin({
beforeCreate(){
// 创建组件的时候不必执行
if(this.$options.router){
_Vue.prototype.$router = this.$options.router
}
}
})
在 new Vue ({ router )}
创建根实例时会执行混入的 beforeCreate
钩子,这里传入的 router
会挂在 this.$options.router
上(this
此时就是创建出的根实例),将传入的 router
赋值给 _Vue.prototype.$router
,就会在以后创建的所有 Vue
实例上添加 $router
属性。且此方法只会在创建根实例时执行一次,因为在创建组件时,不会传入 router
选项。
完整代码
js
let _Vue = null
export default class VueRouter {
static install(Vue){
// 判断当前插件是否已经被安装
if(VueRouter.install.installed) return
VueRouter.install.installed = true
// 把 Vue 构造函数记录到全局变量中
_Vue = Vue
// 创建根实例时,往所有 Vue 实例上添加 $router 属性
_Vue.mixin({
beforeCreate(){
if(this.$options.router){
_Vue.prototype.$router = this.$options.router
}
}
})
}
}