# 插件源码分析

# 背景

在使用vue-router时,有一个步骤:

import VueRouter from 'vue-router'
import Vue from 'vue'

Vue.use(VueRouter)

Vue.use是Vue开放出得一个接口用于调用插件,use方法会调用插件的install方法,并传入Vue构造函数。

# VueRouter的install方法

源码地址 (opens new window)

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
}
  1. 通过在install方法上添加和检查installed属性避免重复执行
  2. 每个组件内都会有一个_routerRoot指向根组件实例
  3. 每个组件的$router$route属性都指向根组件实例的_router和_route
  4. 如果我们想要在组件实例上挂载一些属性和方法,可以通过mixin和钩子函数来实现
  5. 插件注册了全局组件RouterView和RouterLink

# registerRouteInstance

更新组件实例

上次更新: 2/13/2025, 3:29:47 AM