經(jīng)常的猿诸,業(yè)務(wù)中需要用到一些全局的組件婚被,類似Toast、彈窗等梳虽,如果我們在每個頁面都單獨的去引入的話址芯,就會比較麻煩,那么,如何將組件作為全局組件調(diào)用呢谷炸?這樣的好處是在每個頁面調(diào)用的時候北专,不需要引入,直接調(diào)用旬陡,并將它掛載在body元素中拓颓,不會對我們的頁面樣式造成影響。
下面我們來看看如何自定義一個全局組件描孟。
以一個Toast舉例
在components文件夾里录粱,創(chuàng)建一個Notice.vue。
<template>
<div class="alert">
<div class="alert-container" v-for="item in alerts" :key="item.id">
<div class="alert-content">{{item.content}}</div>
</div>
</div>
</template>
因為需要用到alerts画拾,所以創(chuàng)建一個alerts數(shù)組啥繁。
在create()里,需要做一個id的自增控制青抛。
name:'notice',
data() {
return {
alerts: []
}
},
created () {
// id自增控制
this.id = 0;
}
代表來一條alert旗闽,就把id置為0,然后自增一下蜜另。
然后在里面添加2個方法适室,add()和del()。
add用來創(chuàng)建一個新的alert举瑰。
add(options) {
//id放在this里捣辆,所以不是響應(yīng)式的
const id = 'id_'+(this.id++);
//把用戶傳進來的options展開,和id進行合并
const _alert = { ...options, id: id };
this.alerts.push(_alert);
// 自動關(guān)閉
const duration = options.duration || 1; //單位秒
setTimeout(() => {
this.del(id)
},duration*1000);
},
del(id) {
for(let i = 0;i < this.alerts.length; i++) {
const element = this.alerts[i];
if(element.id === id) {
this.alerts.splice(i,1);
break;
}
}
}
完善一下樣式
<style scoped lang="stylus">
.alert {
position: fixed;
width: 100%;
top: 30px;
left: 0;
text-align: center;
.alert-content {
display: inline-block;
padding: 8px;
background: #fff;
margin-bottom: 10px;
}
}
</style>
寫完組件之后此迅,如何全局的調(diào)用它汽畴?
- 最快的方式就是,直接使用別人寫好的api耸序,比如cube-ui里的createAPI忍些。
在main.js里引入createAPI
import { createAPI } from 'cube-ui';
import Notice from './components/Notice.vue';
//創(chuàng)建$createNotice
createAPI(Vue,Notice,true); //參數(shù)3表示單例模式
然后在需要調(diào)用Notice的地方,比如Home.vue里
const notice = this.$createNotice(); //表示創(chuàng)建了一個notice實例坎怪,掛載在body上
notice.add({content:'lalala',duration:2}) //調(diào)用add方法
- 我們自定義一個服務(wù)罢坝,全局調(diào)用Notice
先創(chuàng)建一個services文件夾,創(chuàng)建一個notice.js
import Notice from '@/components/Notice.vue';
import Vue from 'vue';
// 給Notice添加一個創(chuàng)建組件實例的方法搅窿,可以動態(tài)編譯自身模板并掛載
Notice.getInstance = props => {
// 創(chuàng)建一個Vue實例
const instance = new Vue({
// 渲染函數(shù): 用于渲染指定模板為虛擬DOM
// h是一個渲染函數(shù)嘁酿,可以把我們傳入的模板編譯成虛擬DOM
render(h){
// <Notice foo="bar"></Notice>
return h(Notice, {props})
}
}).$mount(); // 執(zhí)行掛載
// $mount() 是outerHTML,所以$mount('body')是不可以的男应,會替換body闹司。
// 所以不指定選擇器,則模板將被渲染為文檔之外的元素
// 必須使用原生的dom api把它插入文檔中
// $el是渲染的Notice中真正的dom元素
document.body.appendChild(instance.$el);
// 獲取Notice實例 instance是vue實例殉了,instance.$children取出實例下的虛擬DOM元素
// $children指的是當(dāng)前Vue實例中包含的所有組件實例 $children[0]就是根开仰,即是Notice實例
const notice = instance.$children[0];
return notice;
}
接下來設(shè)計一個單例模式拟枚,在全局范圍唯一的創(chuàng)建一個Notice實例薪铜,保證它的唯一性
let msgInstance = null;
function getInstance() {
msgInstance = msgInstance || Notice.getInstance();
return msgInstance;
}
暴露接口
export default {
// info方法众弓,參數(shù)給一個默認值
info({duration=2,content=''}){
getInstance().add({
content,duration
});
}
}
在創(chuàng)建完這個notice.js后,需要去main.js注冊
import notice from '@/services/notice';
Vue.prototype.$notice = notice;
最后去Home.vue里使用$notice隔箍。
this.$notice.info({
duration: 3,
content: '一些消息內(nèi)容'
})
這樣就實現(xiàn)了自定義全局組件谓娃,并調(diào)用