詳解用vue編寫彈出框組件
前言
最近研究了用vue編寫彈出框的組件,發(fā)現(xiàn)其實(shí)這里面的門道還是有很多的。這篇文完全是用來記錄總結(jié)下最近的學(xué)習(xí)成果,同時也希望能夠幫得上正在學(xué)習(xí)糾結(jié)的你~ps:本文假設(shè)你已經(jīng)了解vue2.0相關(guān)框架,因此適合有一定vue2.0基礎(chǔ)的同學(xué)閱讀。
設(shè)計(jì)組件的思考
其實(shí)單純的編寫一個彈出框組件并不難,寫一個模板,然后用v-if或者v-show指令還控制組件的出現(xiàn)與消失。真正困擾我的是,這個組件的調(diào)用方式,這個問題糾結(jié)了我好久。
調(diào)研了下資料,有些人建議,直接把組件標(biāo)簽插進(jìn)模板中,然后通過直接控制組件的顯示隱藏來控制組件。這樣寫有好處,就是結(jié)構(gòu)清晰,一目了然,人家一看你的代碼就知道你這個頁面可能會有彈出框,并且編寫的組件就更容易,只需關(guān)注內(nèi)部方法就好了,也不存在事件調(diào)用的困擾,維護(hù)起來也特別容易。但是缺點(diǎn)也很明顯,如果有多個彈窗,并且不知道會有幾個彈窗的情況下,感覺就不太好做,并且這種提前寫模板的形式,難免會在不彈窗的時候要下載一些js文件,有可能會造成性能浪費(fèi)。
也有些人建議,在寫好的彈出框組件之外再做一層封裝,通過動態(tài)調(diào)用的方式來控制彈出框的顯示與隱藏。這樣寫的好處是不用事先在模板里面寫好該組件的標(biāo)簽,只需要在想調(diào)用的地方調(diào)用下該組件,就實(shí)現(xiàn)了按需使用的目的,符合之前傳統(tǒng)前端框架的編碼習(xí)慣。缺點(diǎn)就是感覺代碼寫起來比較復(fù)雜,層層嵌套,并且感覺這個與MVVM模式的狀態(tài)驅(qū)動界面的思想相違背。
于是我天秤座的糾結(jié)病犯了,在選擇哪種技術(shù)方案的問題上,思考了很久。但是網(wǎng)上搜了很多,發(fā)現(xiàn)還是后一種實(shí)現(xiàn)方法用的人比較多。后來我又研究了了elementUI和iView的彈出框組件,他們也是沿用的后一種方法,想了一下后一種方法雖然代碼易讀性不強(qiáng),但是它真正模擬了瀏覽器默認(rèn)的alert事件,在用戶需要的地方來調(diào)用,一方面節(jié)省了代碼量,另一方面也很容易解決多個彈窗的情況。最后還是決定用這種模式寫一個簡單的彈出框組件。主要是體會這其中的機(jī)理。廢話不多說,來上干貨了。有啥不對的地方還請大家多多指教。(ps:對于天秤座的我,雖然選擇了后一種方法,但是內(nèi)心還是鐘愛第一種方法,并且后一種方法并沒有足夠的理由說服我呀,不知道哪位有識之士能夠幫忙點(diǎn)醒一下我,晚輩感激不盡)。
alert組件設(shè)計(jì)
單獨(dú)的設(shè)計(jì)alert彈出框的邏輯是很簡單的,我就直接上代碼了:
<template>
<transition name='fade'>
<div class="alert" v-if="showAlert">
<div class="wrap">
<div class="head">{{title}}</div>
<div class="body">
<slot>
<p>{{message}}</p>
</slot>
</div>
<div class="foot">
<div v-if="type === 'confirm'">
<button class="btn-base" @click="sure">確定</button>
<button class="btn-gray" @click="cancel">取消</button>
</div>
<div v-else-if="type === 'inform'">
<button class="btn-base" @click="cancel">知道了</button>
</div>
</div>
</div>
</div>
</transition>
</template>
<script>
export default {
name: 'alert',
data() {
return {
showAlert: false,
};
},
props: {
title: {
type: String,
default: '提示',
},
message: {
type: String,
},
type: { // 可以有confirm, 和inform兩個類型
type: String,
default: 'confirm',
validator(value) {
return value === 'confirm' || value === 'inform';
},
},
sureBtn: {
type: Function,
},
cancelBtn: {
type: Function,
},
context: {
type: Object,
},
},
methods: {
cancel() {
if (this.cancelBtn) {
this.cancelBtn.apply(this.context);
}
this.close();
},
sure() {
if (this.sureBtn) {
this.sureBtn.apply(this.context);
}
this.close();
},
show() {
this.showAlert = true;
},
close() {
this.showAlert = false;
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang='scss'>
.alert {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0, 0.8);
z-index: 1000;
transition: all .3s ease-in-out;
}
.wrap {
position: absolute;
z-index: 1002;
min-width: 400px;
background: #fff;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 4px;
}
.head {
height: 40px;
line-height: 40px;
border-bottom: 1px solid #dedede;
padding-left: 10px;
color: #333;
}
.body {
padding: 40px 20px;
text-align: center;
}
.foot {
height: 50px;
text-align: center;
button {
margin-right: 20px;
&:last-child {
margin-right: 0;
}
}
}
</style>
這里只是寫了簡單的功能,并沒有考慮更復(fù)雜的情況,比如按鈕顏色定制,大小定制,z-index層級的考慮,遮罩層的統(tǒng)一管理等等,只是為了掌握編寫彈出框的主要思想,所以沒有寫太多的情況。這里只細(xì)分了是確認(rèn)框還是通知框,可以定制彈出框的內(nèi)容、標(biāo)題等一些簡單的常規(guī)操作。
其實(shí)這個組件寫好,就可以在頁面用起來了,直接在對應(yīng)頁面插入這段,可以也可以用:
<!--template-->
<button @click="showAlert">點(diǎn)我</button>
<alert ref="alert">我是一個確認(rèn)框</alert>
<!--javascript-->
...
methods: {
showAlert() {
this.$refs.alert.show();
}
}
...
當(dāng)然,如果真要這么用,這個組件還是需要修改一些東西的,比如事件拋出,當(dāng)點(diǎn)擊確定或者取消按鈕的時候,需要emit對應(yīng)的事件,以提供給父組件捕獲,并做相應(yīng)的處理。
動態(tài)插入到頁面中
為了能讓組件動態(tài)的插入到頁面中,需要對上面的組件進(jìn)行封裝,利用Vue.extend機(jī)制,可以輕松的做到這種封裝,直接上代碼:
import Vue from 'vue';
import alert from './alert';
const AlertConstructor = Vue.extend(alert);
const div = document.createElement('div');
AlertConstructor.show = (options) => {
document.body.appendChild(div);
options.type = 'inform';
const propsData = Object.assign({}, options);
const alertInstance = new AlertConstructor({
propsData,
}).$mount(div);
alertInstance.show();
};
AlertConstructor.confirm = (options) => {
document.body.appendChild(div);
options.type = 'confirm';
const propsData = Object.assign({}, options);
const alertInstance = new AlertConstructor({
propsData,
}).$mount(div);
alertInstance.show();
};
export default AlertConstructor;
這里,show對應(yīng)的是通知框,confirm對應(yīng)的是確認(rèn)框。我知道這種封裝有點(diǎn)簡單了,有很多情況沒有考慮,比如有多個彈出框時的處理等。這里只是做了簡單的封裝,為的就是讓大家明白此種封裝主要思路是什么。
總結(jié)
這篇文章僅僅是對自己這幾天摸索彈出框組件問題的一個簡短的總結(jié)與思考。可能還不是很成熟,當(dāng)做拋磚引玉吧,歡迎大家多多提意見。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue3中el-table實(shí)現(xiàn)表格合計(jì)行的示例代碼
這篇文章主要介紹了vue3中el-table實(shí)現(xiàn)表格合計(jì)行,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01
Vue源碼學(xué)習(xí)之?dāng)?shù)據(jù)初始化
這篇文章主要為大家介紹了Vue源碼學(xué)習(xí)之?dāng)?shù)據(jù)初始化實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
vue+element表格實(shí)現(xiàn)多層數(shù)據(jù)的嵌套方式
這篇文章主要介紹了vue+element表格實(shí)現(xiàn)多層數(shù)據(jù)的嵌套方式,具有很好的參考價值。希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
前端VUE雙語實(shí)現(xiàn)方案詳細(xì)教程
在項(xiàng)目需求中我們會遇到國際化的中英文切換,這篇文章主要給大家介紹了關(guān)于前端VUE雙語實(shí)現(xiàn)方案的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-08-08
vue.js實(shí)現(xiàn)開關(guān)(switch)組件實(shí)例代碼
這篇文章介紹了vue.js實(shí)現(xiàn)開關(guān)(switch)組件的實(shí)例代碼,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06

