系列文章目录
1、vue-router源码解析(一)
2、vue-router源码解析(二) —— install
前言
上一篇简单介绍了下vue-router的源码大体思路框架,本篇详细解析下VueRouter是如何安装挂载的~
一、index.js中的install
VueRouter 对象是在 src/index.js 中暴露出来的,它有一个静态的 install 方法:
// index.js
// 引入install模块
import {
install } from './install'
// 定义VueRouter对象
export default class VueRouter {
static install: () => void
...
}
VueRouter.install = install
...
// 浏览器环境下,若有Vue环境,自动挂载VueRouter插件
if (inBrowser && window.Vue) {
window.Vue.use(VueRouter)
}
将导入的Install赋值给了VueRouter对象的install静态方法,在最后判定当为浏览器环境,执行window.Vue.use(VueRouter)
挂载插件时,实际上Vue实例的use(VueRouter)
就是使用的VueRouter对象自身的install方法,进行插件的安装。
install是一个单独的模块,下面来具体看一下。
二、install.js
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 就是 registerRouteInstance 方法,调用的就是这个方法
i(vm, callVal)
}
}
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)
}
})
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方法,用于
Vue.use(VueRouter)
调用来安装VueRouter插件。 export let _Vue
定义_Vue变量,_Vue = Vue
用于保存Vue实例对象, export暴露出去,目的是其他模块方便对Vue实例的引用,使用其方法和属性,而又不用引入整个vue依赖包,增大打包体积。if (install.installed && _Vue === Vue) return
判定是否已经安装,定义一个installed属性,若为true且已有Vue的引用(只有调用了install方法才有install.installed = true和 _Vue === Vue),表示已安装过,否则退出install方法。这样可以保证只安装一次。- 定义了
registerInstance
方法,let i = vm.$options._parentVnode
至少存在一个 VueComponent 时, _parentVnode 属性才存在 Vue.mixin({...})
混入生命周期的处理,在beforeCreate
节点响应式定义_route属性,Vue.util.defineReactive(this, '_route', this._router.history.current)
,在destroyed
节点销毁实例- 用
Object.defineProperty()
在Vue.prototype
上挂载$router,$route
属性(只读模式) Vue.component('RouterView', View),Vue.component('RouterLink', Link)
全局注册组件