Vue源码分析-Vue.use和vue-router

Vue.use是Vue注册plugin的一种方法,那么这个过程当中发生了什么?经过源码来看一下,vue注册plugin的过程。vue

这里咱们以vue-router为例,顺便看一下vue-router的实现原理。node

Vue.use源码分析

关于如何寻找源码,经过查找响应npm包的package.json文件中的main属性,这就是咱们引入npm包的入口文件的路径。vue-router

function initUse (Vue) {
  Vue.use = function (plugin) {
    var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    var args = toArray(arguments, 1);
    args.unshift(this);
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args);
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args);
    }
    installedPlugins.push(plugin);
    return this
  };
}
复制代码

查看这部分源码,咱们能够发现vue首先判断这个插件是否被注册过,不容许重复注册。 而且接收的plugin参数的限制是Function | Object两种类型。 对于这两种类型有不一样的处理。npm

若是咱们传入的plugin(Vue.use的第一个参数)的install是一个方法。也就是说若是咱们传入一个对象,对象中包含install方法,那么咱们就调用这个plugin的install方法并将整理好的数组当成参数传入install方法中。 => plugin.install.apply(plugin, args) 若是咱们传入的plugin就是一个函数,那么咱们就直接调用这个函数并将整理好的数组当成参数传入。 => plugin.apply(null, args) 以后给这个插件添加至已经添加过的插件数组中,标示已经注册过 => installedPlugins.push(plugin) 最后返回Vue对象。json

看看vue-router的注册过程

首先咱们按照上面说的方法找到vue-router的源码数组

import View from './components/view'
import Link from './components/link'

export let _Vue

// 这里就是在Vue.use中会别执行的install方法
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实例混入beforeCreate钩子操做(后续能够继续看一下mixin的源码)
 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.prototype定义$router$route 属性(方便全部组件能够获取这两个属性)
 Object.defineProperty(Vue.prototype, '$router', {
   get () { return this._routerRoot._router }
 })

 Object.defineProperty(Vue.prototype, '$route', {
   get () { return this._routerRoot._route }
 })
 // Vue上注册router-link和router-view两个组件
 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.js)bash

该方法内主要作了如下三件事:app

  1. 对Vue实例混入beforeCreate钩子操做(在Vue的生命周期阶段会被调用)
  2. 经过Vue.prototype定义router、router、route 属性(方便全部组件能够获取这两个属性)
  3. Vue上注册router-link和router-view两个组件
相关文章
相关标签/搜索