相信这个use方法大家肯定不陌生,加载路由插件Vue.use(VueRouter),加载状态管理插件Vue.use(Vuex),加载Element插件Vue.use(Button).use(Input),那它底层源码究竟是怎么实现加载Vue相关的插件和链式调用的,下面一步一步带各位读者"掰开揉碎"实现代码。
Vue.use方法介绍
先上官网对Vue.use的方法介绍:
安装
Vue.js插件。如果插件是一个对象,必须提供install方法。如果插件是一个函数,它会被作为install方法。install方法调用时,会将Vue作为参数传入。该方法需要在调用
new Vue()之前被调用。当 install 方法被同一个插件多次调用,插件将只会被安装一次。
上面的介绍主要是对use方法的功能和使用的注意提示,这里注意的是use方法传入的参数数量其实是没有限制的,支持多个参数;还有第一个参数可以传入带install属性方法的对象或者是函数。
Vue.use源码分析
直接上Vue.use的源码:
// ...
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
};
// ...
这里分成是4个步骤进行分析:
第一步:只调用一次install
实现的效果就是当install被多次调用的时候,插件只会被安装一次。检查当前的Vue对象里的_installedPlugins数组上是否有当前插件对象,如果存在则直接完成返回当前的Vue对象(也就是代码里面看到的return this)
Vue.use = function (plugin) {
// 第一步:当install被多次调用的时候,插件只会被安装一次。
var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// ....
}
第二步:把arguments转换成数组
处理参数,把arguments上的其余参数(排除第一个)转换成一个新的数组,把当前的Vue对象(也就是代码中的this)作为新数组的第一个参数
// 将类数组对象转换成数组,start就是转换的起始位置
function toArray (list, start) {
start = start || 0;
var i = list.length - start;
var ret = new Array(i);
while (i--) {
ret[i] = list[i + start];
}
return ret
}
Vue.use = function (plugin) {
// ...
/**
* 第二步:
* arguments删除第一个参数后转换成真正的数组,并且添加this作为数组的第一个元素
* 例如:Vue.use(MyTest, 1, 2, 3); 经过处理后新的数组:args = [this, 1, 2, 3]
*/
var args = toArray(arguments, 1);
// 往新数组最前面添加一个this
args.unshift(this);
}
第三步:调用插件的install方法
判断use方法的第一个参数的install属性是否为函数,又或者第一个参数是否为函数,如果有一个满足则执行apply方法调用第一个参数函数,并且把use方法剩余的参数传入。
Vue.use = function (plugin) {
// ...
/**
* 第三步:
* 假设现在:Vue.use(MyTest, 1, 2, 3);
* 1. 第一个判断表达式中的plugin就是MyTest,也就是判断MyTest上的install属性是否为函数,如果是则使用apply方法调用MyTest.install函数,并且把this绑定在MyTest上。
* 2. 第二个判断表达式中判断plugin(MyTest)是否为函数,如果是则传入剩余参数使用apply直接执行调用。
*/
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args);
// 另外一种Vue.use的第一参数是函数,那么就直接数组作为参数传入,例如:Mytest(this, 1, 2, 3, 4, 5),这里的this其实就是Vue
} else if (typeof plugin === 'function') {
plugin.apply(null, args);
}
}
第四步:返回this
为_installedPlugins数组末尾添加当前插件对象,然后返回this,也就是当前的Vue对象。这里返回this就是为了能让use方法能够支持链式调用。
// 将类数组对象转换成数组,start就是转换的起始位置
function toArray (list, start) {
start = start || 0;
var i = list.length - start;
var ret = new Array(i);
while (i--) {
ret[i] = list[i + start];
}
return ret
}
Vue.use = function (plugin) {
// ...
// 第四步:添加插件plugin到this._installedPlugins数组末尾,返回this
installedPlugins.push(plugin);
// 这个返回this,能够实现链式调用
return this
}
如果读者发现有不妥或者可以改善的地方,欢迎在评论区指出。如果觉得写得不错或者对你有所帮助,可以点赞、评论、转发分享,谢谢~