詳解用vue編寫彈出框組件
前言
最近研究了用vue編寫彈出框的組件,發(fā)現(xiàn)其實(shí)這里面的門道還是有很多的。這篇文完全是用來(lái)記錄總結(jié)下最近的學(xué)習(xí)成果,同時(shí)也希望能夠幫得上正在學(xué)習(xí)糾結(jié)的你~ps:本文假設(shè)你已經(jīng)了解vue2.0相關(guān)框架,因此適合有一定vue2.0基礎(chǔ)的同學(xué)閱讀。
設(shè)計(jì)組件的思考
其實(shí)單純的編寫一個(gè)彈出框組件并不難,寫一個(gè)模板,然后用v-if或者v-show指令還控制組件的出現(xiàn)與消失。真正困擾我的是,這個(gè)組件的調(diào)用方式,這個(gè)問(wèn)題糾結(jié)了我好久。
調(diào)研了下資料,有些人建議,直接把組件標(biāo)簽插進(jìn)模板中,然后通過(guò)直接控制組件的顯示隱藏來(lái)控制組件。這樣寫有好處,就是結(jié)構(gòu)清晰,一目了然,人家一看你的代碼就知道你這個(gè)頁(yè)面可能會(huì)有彈出框,并且編寫的組件就更容易,只需關(guān)注內(nèi)部方法就好了,也不存在事件調(diào)用的困擾,維護(hù)起來(lái)也特別容易。但是缺點(diǎn)也很明顯,如果有多個(gè)彈窗,并且不知道會(huì)有幾個(gè)彈窗的情況下,感覺(jué)就不太好做,并且這種提前寫模板的形式,難免會(huì)在不彈窗的時(shí)候要下載一些js文件,有可能會(huì)造成性能浪費(fèi)。
也有些人建議,在寫好的彈出框組件之外再做一層封裝,通過(guò)動(dòng)態(tài)調(diào)用的方式來(lái)控制彈出框的顯示與隱藏。這樣寫的好處是不用事先在模板里面寫好該組件的標(biāo)簽,只需要在想調(diào)用的地方調(diào)用下該組件,就實(shí)現(xiàn)了按需使用的目的,符合之前傳統(tǒng)前端框架的編碼習(xí)慣。缺點(diǎn)就是感覺(jué)代碼寫起來(lái)比較復(fù)雜,層層嵌套,并且感覺(jué)這個(gè)與MVVM模式的狀態(tài)驅(qū)動(dòng)界面的思想相違背。
于是我天秤座的糾結(jié)病犯了,在選擇哪種技術(shù)方案的問(wèn)題上,思考了很久。但是網(wǎng)上搜了很多,發(fā)現(xiàn)還是后一種實(shí)現(xiàn)方法用的人比較多。后來(lái)我又研究了了elementUI和iView的彈出框組件,他們也是沿用的后一種方法,想了一下后一種方法雖然代碼易讀性不強(qiáng),但是它真正模擬了瀏覽器默認(rèn)的alert事件,在用戶需要的地方來(lái)調(diào)用,一方面節(jié)省了代碼量,另一方面也很容易解決多個(gè)彈窗的情況。最后還是決定用這種模式寫一個(gè)簡(jiǎn)單的彈出框組件。主要是體會(huì)這其中的機(jī)理。廢話不多說(shuō),來(lái)上干貨了。有啥不對(duì)的地方還請(qǐng)大家多多指教。(ps:對(duì)于天秤座的我,雖然選擇了后一種方法,但是內(nèi)心還是鐘愛(ài)第一種方法,并且后一種方法并沒(méi)有足夠的理由說(shuō)服我呀,不知道哪位有識(shí)之士能夠幫忙點(diǎn)醒一下我,晚輩感激不盡)。
alert組件設(shè)計(jì)
單獨(dú)的設(shè)計(jì)alert彈出框的邏輯是很簡(jiǎn)單的,我就直接上代碼了:
<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兩個(gè)類型 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>
這里只是寫了簡(jiǎn)單的功能,并沒(méi)有考慮更復(fù)雜的情況,比如按鈕顏色定制,大小定制,z-index層級(jí)的考慮,遮罩層的統(tǒng)一管理等等,只是為了掌握編寫彈出框的主要思想,所以沒(méi)有寫太多的情況。這里只細(xì)分了是確認(rèn)框還是通知框,可以定制彈出框的內(nèi)容、標(biāo)題等一些簡(jiǎn)單的常規(guī)操作。
其實(shí)這個(gè)組件寫好,就可以在頁(yè)面用起來(lái)了,直接在對(duì)應(yīng)頁(yè)面插入這段,可以也可以用:
<!--template--> <button @click="showAlert">點(diǎn)我</button> <alert ref="alert">我是一個(gè)確認(rèn)框</alert> <!--javascript--> ... methods: { showAlert() { this.$refs.alert.show(); } } ...
當(dāng)然,如果真要這么用,這個(gè)組件還是需要修改一些東西的,比如事件拋出,當(dāng)點(diǎn)擊確定或者取消按鈕的時(shí)候,需要emit對(duì)應(yīng)的事件,以提供給父組件捕獲,并做相應(yīng)的處理。
動(dòng)態(tài)插入到頁(yè)面中
為了能讓組件動(dòng)態(tài)的插入到頁(yè)面中,需要對(duì)上面的組件進(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對(duì)應(yīng)的是通知框,confirm對(duì)應(yīng)的是確認(rèn)框。我知道這種封裝有點(diǎn)簡(jiǎn)單了,有很多情況沒(méi)有考慮,比如有多個(gè)彈出框時(shí)的處理等。這里只是做了簡(jiǎn)單的封裝,為的就是讓大家明白此種封裝主要思路是什么。
總結(jié)
這篇文章僅僅是對(duì)自己這幾天摸索彈出框組件問(wèn)題的一個(gè)簡(jiǎn)短的總結(jié)與思考。可能還不是很成熟,當(dāng)做拋磚引玉吧,歡迎大家多多提意見(jiàn)。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
如何解決element-ui動(dòng)態(tài)加載級(jí)聯(lián)選擇器默認(rèn)選中問(wèn)題
這篇文章主要介紹了如何解決element-ui動(dòng)態(tài)加載級(jí)聯(lián)選擇器默認(rèn)選中問(wèn)題,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-09-09vue router學(xué)習(xí)之動(dòng)態(tài)路由和嵌套路由詳解
本篇文章主要介紹了vue router 動(dòng)態(tài)路由和嵌套路由,詳細(xì)的介紹了動(dòng)態(tài)路由和嵌套路由的使用方法,有興趣的可以了解一下2017-09-09Vue中的transition封裝組件的實(shí)現(xiàn)方法
這篇文章主要介紹了Vue中的transition封裝組件的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Vue3響應(yīng)式對(duì)象是如何實(shí)現(xiàn)的(2)
這篇文章主要介紹了Vue3響應(yīng)式對(duì)象是如何實(shí)現(xiàn)的,文章基于上篇文章展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-08-08