vue2.6版本源码阅读-Vue.use()全局api

356 阅读2分钟

Vue.use()源码阅读

用途

Vue.use()通常用于开发自定义plugin使用,比如

  1. 添加全局混入(vue-router、vuex等官方插件均在install函数中调用Vue.mixin({ beforeCreate: fn })实例化插件);
  2. 开发第三方组件,例如实现自定义加载中效果,为Vue.prototype上添加公共方法;

源码阅读

export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) { // 维护installedPlugins 避免多次注册 之前有注册过就直接返回
      return this
    }

    // additional parameters
    const args = toArray(arguments, 1)
    args.unshift(this) // 第一个参数是Vue 优势:编写第三方插件不用再额外引入import Vue
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args) // install函数的第一个参数是Vue
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
  }
}

源码解析

  1. Vue.use()接收两种类型的入参,Object类型 or Function类型,object类型会调用install(),所以必须要提供install属性;function类型会直接被当做install调用;并且将Vue作为第一个参数传入,这样做的优势:在编写第三方插件不再额外引入import Vue库,压缩代码体积;
 const args = toArray(arguments, 1)
    args.unshift(this) // 第一个参数是Vue 优势:编写第三方插件不用再额外引入import Vue
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args) // install函数的第一个参数是Vue
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
  1. 在Vue上维护私有属性_installedPlugins判断是否重复注册同一个插件,有重复注册则返回,否则添加到私有属性_installedPlugins中,installedPlugins.push(plugin);
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
if (installedPlugins.indexOf(plugin) > -1) { // 维护installedPlugins 避免多次注册 之前有注册过就直接返回
  return this
}
  1. 官网上强调要在new Vue(options)实例化之前调用,为什么呢?回顾下Vue.use()使用的初衷,当我们在Vue.prototype上添加原型方法或者调用Vue其他全局api例如directive、filter、component、mixin等,实例化Vue后所有组件实例上都会有扩展的方法、指令、或组件,这一切,是如何实现的呢?

    Vue.prototype很好理解,全局api【directive、filter、component、mixin】的实现都是在Vue.options上扩展属性,实例化new Vue会调用_init(),_init()的关键是将Vue.options与实例对象vm.options合并,实例化组件也会将Vue.options作为原型创建组件的options合并,实例化组件也会将Vue.options作为原型创建组件的options上,源码如下:

// merge options
if (options && options._isComponent) {
  initInternalComponent(vm, options)
} else {
  vm.$options = mergeOptions(
    resolveConstructorOptions(vm.constructor),
    options || {},
    vm
  )
}
export function initInternalComponent (vm: Component, options: InternalComponentOptions) {
  const opts = vm.$options = Object.create(vm.constructor.options)
  ... ...
}

同时,_init()会进行生命周期钩子初始化,同时调用beforeCreate()与created()钩子,这样,经过在初始化之前调用Vue.use()才可以将属性扩展到实例化vue上

  1. 在源码的最后return this,可以方便我们链式调用use()方法

最后,在阅读别人代码的过程,思考与积累是我们提升自己的“捷径”

知名不惧,日日自新