Vue源码学习之组件安装器(Vue.use(plugins[,options]))

145 阅读1分钟
  • 之前在使用Vue做项目时,经常会用到
Vue.use(plugins[,options])

这种方式去将一个组件绑定到Vue的全局实例上,这样,我们就不需要在每个页面都引入和注册组件便可以直接使用了,例如:Vant组件的挂载:

import Vue from "vue";
import {
    Tabbar,
    TabbarItem,
    Toast,
    Icon,
    Skeleton,
    Swipe,
    SwipeItem,
    Dialog,
    Image,
    Lazyload,
    NavBar,
    ImagePreview,
    CellGroup,
    Cell,
    Field,
    Button,
    NumberKeyboard,
    SwitchCell,
    Notify,
    Popup,
    PullRefresh,
    Calendar,
    Picker,
    List,
    Row,
    Col,
    Loading,
    Tag,
    Collapse,
    CollapseItem,
    Tab,
    Tabs,
    Sticky,
    Switch,
    Search,
    NoticeBar,
    Sidebar,
    SidebarItem
} from "vant";

Vue.use(Tabbar);
Vue.use(TabbarItem);
Vue.use(Toast);
Vue.use(Icon);
Vue.use(Skeleton);
Vue.use(Swipe);
Vue.use(SwipeItem);
Vue.use(Dialog);
Vue.use(Image);
Vue.use(Lazyload);
Vue.use(NavBar);
Vue.use(ImagePreview);
Vue.use(CellGroup);
Vue.use(Cell);
Vue.use(Field);
Vue.use(Button);
Vue.use(NumberKeyboard);
Vue.use(SwitchCell);
Vue.use(Notify);
Vue.use(Popup);
Vue.use(PullRefresh);
Vue.use(Calendar);
Vue.use(Picker);
Vue.use(List);
Vue.use(Row);
Vue.use(Col);
Vue.use(Loading);
Vue.use(Tag);
Vue.use(Collapse);
Vue.use(CollapseItem);
Vue.use(Tabs);
Vue.use(Tab);
Vue.use(Sticky);
Vue.use(Switch);
Vue.use(Search);
Vue.use(NoticeBar);
Vue.use(Sidebar);
Vue.use(SidebarItem);

最近深入学习了一下Vue的源码,于是便研究了一下Vue的这种组件挂载方式的原理和实现方式,并写了一个简单的实例模拟这个组件挂载过程。具体细节不多讲,请看下面源码,源码中有注释:

Vue.js 本文件旨在模拟Vue,但仅为了演示组件挂载过程,其他代码未实现

const {initUse} = require("./VueUse");
// 模拟Vue构造函数
let Vue = function () {
    this.version = '__VERSION__';
};
// 模拟Vue的组件挂载方法,此处仅将所给组件挂载到Vue原型链上,省略其他无关步骤
Vue.component = function(name,component){
    Vue.prototype[`$${name}`] = component;
};

// 初始化Vue的use方法,可以通过Vue.use()的方式将组件注册到Vue的全局实例上
initUse(Vue);

module.exports = Vue;
 VueUse.js  本文件即为实现Vue.use的主要逻辑代码

const _ = require("../utils");
/**
 * 初始化Vue的use方法
 * @param Vue   传入Vue对象
 */
module.exports.initUse = function (Vue={}) {
    /**
     * 在Vue上扩展静态方法use,用于挂载插件到Vue的实例上
     * @param plugins   插件对象
     * @returns {Vue}
     */
    Vue.use = function (plugins) {

        // 获取当前Vue实例上的已经安装的插件列表,若要安装的插件已经安装,则直接返回,无需重复安装
        const _installedPlugins = (this._installedPlugins || (this._installedPlugins = []));

        if(_installedPlugins.indexOf(plugins)>-1){
            return this;
        }


        // 安装插件时可能需要传递一些额外的参数,将除plugins之外的其他参数都转化为数组形式
        let args = _.toArray(arguments,1);
        // 将当前Vue实例对象作为第一个参数加入参数数组
        args.unshift(this);
        //如果目标插件存在install方法,则直接调用install方法对插件进行安装
        if(plugins.install&&typeof plugins.install === "function"){
            plugins.install.apply(plugins,args);
        }else if(typeof plugins === "function"){
            //若目标插件不存在install方法,并且目标插件是一个函数,则直接调用该函数
            plugins.apply(plugins,args);
        }
        //将当前插件加入到已安装插件列表
        _installedPlugins.push(plugins);
        return this;
    }
};
 utils.js 工具类


module.exports = {
    toArray: (arrayLike,start=0) => {

        if(arrayLike.length===undefined){
            return arrayLike;
        }

        let i = arrayLike.length - start;
        let res = new Array(i);

        while (i--){
            res[i] = arrayLike[i+start]
        }

        return res;
    }
};

 

 plugins1.js 实例组件1
class MyPlugins{
    constructor(){

    }
    showName(name,age){
        console.log(`你好,我叫${name},今年${age}岁`);

        console.log(`来自:${this.options.from}`);
    }
    install(Vue,options){
        this.options = options;
        Vue.component("myPlugins",this);
    }
}

module.exports = new MyPlugins();

 plugins2.js 实例组件2
class MyPlugins{
    constructor(){

    }
    showName(name,age){
        console.log(`hello,my name is ${name},I'm ${age} years old`);

        console.log(`from:${this.options.from}`);
    }
    install(Vue,options){
        // 传给插件的参数
        this.options = options;
        // 将当前组件注册到Vue实例上
        Vue.component("myPluginsEn",this);
    }

}

module.exports = new MyPlugins();
 test.js 用户测试组件挂载结果

const Vue = require("./Vue");
const MyPlugins = require("./plugins1");
const MyPluginsEn = require("./plugins2");

//将目标组件挂载到Vue实力上
Vue.use(MyPlugins,{from: 'china'})
    .use(MyPluginsEn,{from: 'U.S'});

let vue = new Vue();


//直接调用目标组件下的方法完成调用
vue.$myPlugins.showName('kiner',20);
vue.$myPluginsEn.showName('kanger',18);

 最终输出结果:

到此,组件挂载的简易版本就算完成了。

PS: 本文仅为个人学习Vue源码时的记录,文中若有不妥之处,还请指正,谢谢!