在做 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({ ... }) |