vue 實(shí)現(xiàn)全局使用的loading組件(使用Vue.extend)
在開(kāi)發(fā)中止潘,如果項(xiàng)目比較復(fù)雜,那么頁(yè)面加載往往會(huì)有一個(gè)小空白時(shí)間。當(dāng)然了姑原,頁(yè)面加載速度這些我們必須要去優(yōu)化。但若有時(shí)候網(wǎng)絡(luò)不好了什么的呜舒,總之免不了會(huì)出現(xiàn)白屏锭汛。為了不讓用戶的內(nèi)心在這段時(shí)間內(nèi)過(guò)于寂寞,我們往往需要給頁(yè)面加上 loading 小圈圈,告訴用戶:我們正在努力拽數(shù)據(jù)呢唤殴,親般婆,稍等哈~~
實(shí)現(xiàn)思路
其實(shí),寫(xiě)個(gè)loadign頁(yè)面很簡(jiǎn)單朵逝,關(guān)鍵的是如何讓使用起來(lái)更簡(jiǎn)單蔚袍。
思路一:可能我們一開(kāi)始最容易想起來(lái)的就是,吧loading抽成一個(gè)組件配名,那個(gè)頁(yè)面要用啤咽,那個(gè)頁(yè)面引入就好了,然后注冊(cè)組件渠脉,用v-if或者v-show顯示隱藏宇整。這沒(méi)啥毛病,就是感覺(jué)麻煩了點(diǎn)芋膘,憑什么每個(gè)頁(yè)面都要去引入鳞青?這組件用的頻率高,列表加載索赏,點(diǎn)擊保存盼玄,估計(jì)我們都會(huì)用。
思路二:那既然使用頻率高潜腻,何不將組件做成全局注冊(cè)組件埃儿?這樣就省去了每個(gè)組件引用的代碼。這比思路一要更進(jìn)一步了融涣,但是童番,這樣我們就滿足了嗎?NO! NO! NO! 這不是一個(gè)優(yōu)雅的程序員的風(fēng)格啊威鹿。
假如你和我一樣剃斧,都不是神馬大佬級(jí)別人物。如果同樣有這種需求忽你,而又一時(shí)想不到好辦法幼东,咋辦?
抄唄科雳「罚咳咳,說(shuō)的太直接了點(diǎn)糟秘,應(yīng)該叫借鑒简逮,擅長(zhǎng)于從別人的代碼里面學(xué)習(xí)也是一種能力。
使用vue開(kāi)發(fā)的童鞋尿赚,相比大部分都使用過(guò)element-ui散庶,當(dāng)然element-ui也有l(wèi)oading組件蕉堰,你會(huì)發(fā)現(xiàn)使用時(shí)loading,confirm這些組件悲龟,都是可以用this訪問(wèn)的屋讶,這樣調(diào)用起來(lái)是不是很方便?
點(diǎn)開(kāi)loading組件源碼须教,我們找到了實(shí)現(xiàn)的關(guān)鍵點(diǎn)丑婿。其實(shí)就是下面這代碼
const LoadingConstructor = Vue.extend(loadingVue);
LoadingConstructor.prototype.close = function() {
if (this.fullscreen) {
fullscreenLoading = undefined;
}
afterLeave(this, _ => {
const target = this.fullscreen || this.body
? document.body
: this.target;
removeClass(target, 'el-loading-parent--relative');
removeClass(target, 'el-loading-parent--hidden');
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
this.$destroy();
}, 300);
this.visible = false;
};
其實(shí)就是,使用vue.extend創(chuàng)建構(gòu)造器没卸,然后在構(gòu)造器下掛函數(shù)就好了羹奉。
官方對(duì)vue.extend解釋也很簡(jiǎn)單:使用基礎(chǔ) Vue 構(gòu)造器,創(chuàng)建一個(gè)“子類”约计。參數(shù)是一個(gè)包含組件選項(xiàng)的對(duì)象诀拭。data 選項(xiàng)是特例,需要注意 - 在 Vue.extend() 中它必須是函數(shù)
好煤蚌,這就是我們的思路三了耕挨。有了思路,我們就可以實(shí)現(xiàn)了尉桩,這里我們不需要像elemenet-ui那么復(fù)雜筒占,簡(jiǎn)單點(diǎn)。
剩下的就直接上代碼了哈蜘犁。起個(gè)名字吧翰苫,叫l(wèi)m-loading。
lm-loading.vue
<template>
<div class="loadingBox rowCenter" v-if="visible">
<i class="el-icon-loading font32 gray666"></i>
</div>
</template>
<script>
export default {
name: "LmLoading",
}
</script>
入口文件index.js
import Vue from 'vue'
import lmLoading from './lm-loading'
const LmLoadingConstructor=Vue.extend(lmLoading)
let instance
const initInstance = () => {
instance = new LmLoadingConstructor({
el: document.createElement('div'),
data(){
return {
visible: false,
}
}
})
}
const LmLoading=function (){
if (!instance) {
initInstance()
}
}
LmLoading.show=function (timeout){
return new Promise((resolve,reject)=>{
document.body.appendChild(instance.$el)
instance.visible = true
if(typeof timeout==='number'){
let timeNum=setTimeout(()=>{
clearTimeout(timeNum)
instance.visible=false
},timeout)
}
resolve(true)
})
}
LmLoading.hidden=function (){
instance.visible =false
}
export default LmLoading
如此这橙,調(diào)用也很簡(jiǎn)單
在main.js里面引入
import LmLoading from 'lm-loading'
Vue.use(LmLoading)
Vue.prototype.$lmLoading=LmLoading
使用
this.$lmLoading.show()
this.$lmLoading.hidden()