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