Vue源碼學習之組件安裝器(Vue.use(plugins[,options]))

  • 之前在使用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源碼時的記錄,文中若有不妥之處,還請指正,謝謝!

發佈了24 篇原創文章 · 獲贊 12 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章