vue.use()方法从源码到使用

在做 vue 开发的时候大家一定经常接触 Vue.use() 方法,官网给出的解释是: 通过全局方法 Vue.use() 使用插件;我觉得把使用理解成注册更合适一些,首先看下面常见的注册场景。

1
2
3
4
5
6
7
8
import Router from 'vue-router'
Vue.use(Router)
 
import Vuex from 'vuex'
Vue.use(Vuex)
 
import Echarts from 'echarts'
Vue.prototype.$echarts = Echarts

关于 echarts 的注册很简单,直接挂在 Vue 方法的原型上,通过原型链继承的关系可以在任意一个组件里通过 this.$echarts 访问到 echarts 实例,我们来写一个简单的例子证明一下。

1
2
3
4
5
6
7
8
function myVue(title){
 this.title = title
}
myVue.prototype.myUse = '在原型上添加公共属性'
const A = new myVue('我是实例A')
const B = new myVue('我是实例B')
console.log(A.title, B.title, A.myVue, B.myVue, )
// 我是实例A 我是实例B 在原型上添加公共属性 在原型上添加公共属性

而 Router 和 Vuex 的注册就要去分析 Vue.use() 的源码了,在分析源码之前先总结一下官方对 Vue.use() 方法的说明:

  • 通过全局方法 Vue.use() 使用插件
  • Vue.use 会自动阻止多次注册相同插件
  • 它需要在你调用 new Vue() 启动应用之前完成
  • Vue.use() 方法至少传入一个参数,该参数类型必须是 Object 或 Function,如果是 Object 那么这个 Object 需要定义一个 install 方法,如果是 Function 那么这个函数就被当做 install 方法。在 Vue.use() 执行时 install 会默认执行,当 install 执行时第一个参数就是 Vue,其他参数是 Vue.use() 执行时传入的其他参数。

官网说 Vue.use() 是用来使用插件的,那么传入的 Router 和 Vuex 就是这里指的插件,而这个插件本质上又是一个 install 方法。至于 install 方法内部实现了什么逻辑就由插件自身的业务决定了。

vue.use()源码


下面切入本文的主题。我们知道了vue.use()怎么用还不够,还要知道它的内部是怎么实现的。下面展示源码:

import { toArray } from '../util/index'

export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    const 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.use()源码中采用了flow的语法。flow语法,官方解释是:

Flow is a static type checker for your JavaScript code. It does a lot of work to make you more productive. Making you code faster, smarter, more confidently, and to a bigger scale.

简单的意思就是flow是JavaScript代码的静态类型检查工具。官网链接
使用flow的好处就是:在编译期对js代码变量做类型检查,缩短调试时间, 减少因类型错误引起的bug。我们都知道js是解释执行语言,运行的时候才检查变量的类型,flow可以在编译阶段就对js进行类型检查。

下面将对vue.use()源码进行解读:

1、首先先判断插件plugin是否是对象或者函数:
Vue.use = function (plugin: Function | Object)

2、判断vue是否已经注册过这个插件
installedPlugins.indexOf(plugin) > -1
如果已经注册过,跳出方法

3、取vue.use参数。
const args = toArray(arguments, 1)

4、toArray()取参数
代码:

export function toArray (list: any, start?: number): Array<any> {
    start = start || 0
    let i = list.length - start
    const ret: Array<any> = new Array(i)
    while (i--) {
      ret[i] = list[i + start]
    }
    return ret
  }

let i = list.length - start意思是vue.use()方法传入的参数,除第一个参数外(第一个参数是插件plugin),其他参数都存储到一个数组中,并且将vue对象插入到参数数组的第一位。最后参数数组就是[vue,arg1,arg2,...]

5、判断插件是否有install方法,如果有就执行install()方法。没有就直接把plugin当Install执行。

if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }

plugin.install.apply(plugin, args)将install方法绑定在plugin环境中执行,并且传入args参数数组进install方法。此时install方法内的this指向plugin对象。
plugin.apply(null, args) plugin内的this指向null.

最后告知vue该插件已经注册过installedPlugins.push(plugin)保证每个插件只会注册一次。

Vue.use()有什么用

在 install 里我们可以拿到 Vue 那么和 Vue 相关的周边工作都可以考虑放在 Vue.use() 方法里,比如:

  • directive注册
  • mixin注册
  • filters注册
  • components注册
  • prototype挂载
  • ...

echarts 用 Vue.use() 来注册

main.js

1
2
3
4
5
6
7
import Vue from 'vue'
import echarts from './echarts.js'
Vue.use(echarts)
 
new Vue({
 ...
})

echarts.js

1
2
3
4
5
6
import Echarts from 'echarts'
export default {
 install(Vue){
  Vue.prototype.$echarts = Echarts
 }
}

这样写的好处是可以在 install 的文件里做更多配置相关的工作,main.js 不会变的臃肿,更方便管理。

全局组件用 Vue.use() 来注册

base.js

1
2
3
4
5
6
7
8
import a from './a'
import b from './b'
let components = { a, b }
const installBase = {
 install (Vue) {
  Object.keys(components).map(key => Vue.component(key, components[key]))
 }
}

main.js

1
2
3
4
5
6
7
import Vue from 'vue'
import base from './base.js'
Vue.use(base)
 
new Vue({
 ...
})
posted @ 2020-03-16 16:22  勒布朗_詹姆斯  阅读(1102)  评论(0编辑  收藏  举报