element ui循環(huán)調(diào)用this.$alert 消息提示只顯示最后一個(gè)
需求背景
有一個(gè)需求,使用element-ui 中的$alert 方法提示 用戶幾條信息,不能一次性提示。僅能一條一條的提示,提示完第一條,點(diǎn)擊確定后如果還有待提示消息,就彈出提示第二條,以此類推,直到消耗完所有需要提示的消息結(jié)束;現(xiàn)在模擬復(fù)現(xiàn)一下這個(gè)需求的期望如下圖:
那這還不簡(jiǎn)單??? 我們聽(tīng)完需求心中已經(jīng)想好了代碼怎么寫(xiě)了。于是我們摩拳擦掌 說(shuō)干就干, 一頓 C & V 操作,于是有了下面的代碼:
showMsg(){ for(let i = 0; i < 4; i++){ this.$alert('show message !'+ i,'提示') } }
然后滿心歡喜,胸有成竹的一運(yùn)行,發(fā)現(xiàn)事與愿違,來(lái)看下運(yùn)行的結(jié)果:
我們發(fā)現(xiàn)并沒(méi)有按我們的預(yù)期來(lái)執(zhí)行,而是直接只顯示了最后提示,就結(jié)束了,那么是什么問(wèn)題導(dǎo)致了這個(gè)問(wèn)題的出現(xiàn)呢:
問(wèn)題分析
那我們本著弄清楚事實(shí)的心態(tài)來(lái)搞清楚問(wèn)題發(fā)生的原因,那就翻一翻element-ui 中 $alert 方法到底是怎么實(shí)現(xiàn)的?
首先找到 $alert 的入口,他的入口位于 element/blob/dev/src/index.js Line:199
Vue.prototype.$alert = MessageBox.alert;
我們看到他在Vue 的原型上擴(kuò)展了 $alert 方法,方法指向了 MessageBox.alert
那我們繼續(xù)跟進(jìn) MessageBox.alert Line:161 看看他到底是怎么回事?
我們截取其中的代碼片段:
MessageBox.alert = (message, title, options) => { if (typeof title === 'object') { options = title; title = ''; } else if (title === undefined) { title = ''; } return MessageBox(merge({ title: title, message: message, $type: 'alert', closeOnPressEscape: false, closeOnClickModal: false }, options)); };
我們看到這個(gè)方法代碼比較簡(jiǎn)潔,先是對(duì)參數(shù)進(jìn)行了一些處理,最后把處理后的參數(shù)merge到默認(rèn)的一些參數(shù)上,返回了 MessageBox 這個(gè)方法,根據(jù)他的命名我們大概能猜到 他是一個(gè)類;
MessageBox 類的實(shí)現(xiàn)
const MessageBox = function(options, callback) { // 判斷是否為服務(wù)端 ? 跳過(guò) ... if (Vue.prototype.$isServer) return; // 對(duì)傳入的options 參數(shù)進(jìn)行了判斷,是不是 String 或者 vNode ,然后處理參數(shù)。這里主要是 處理 title 或 message if (typeof options === 'string' || isVNode(options)) { options = { message: options }; if (typeof arguments[1] === 'string') { options.title = arguments[1]; } // 處理了參數(shù) callback , 吧options.callback 賦給 callback ... } else if (options.callback && !callback) { callback = options.callback; } // 判斷是否 可以使用 Promise 對(duì)象, if (typeof Promise !== 'undefined') { // 就把參數(shù)包裝到 Promise 中 push 進(jìn)入 msgQueue 隊(duì)列中... return new Promise((resolve, reject) => { // eslint-disable-line msgQueue.push({ options: merge({}, defaults, MessageBox.defaults, options), callback: callback, resolve: resolve, reject: reject }); // 執(zhí)行 showNextMsg() 方法 showNextMsg(); }); } else { // 不支持 promise 就直接 吧參數(shù) push 進(jìn)隊(duì)列,再執(zhí)行 showNextMsg msgQueue.push({ options: merge({}, defaults, MessageBox.defaults, options), callback: callback }); showNextMsg(); } };
從上面的代碼中 我們知道,
- 處理了傳入的參數(shù)
- 維護(hù)了一個(gè) msgQueue 隊(duì)列,用于存放 不同場(chǎng)景(是否支持Promise)下的參數(shù)
- 都執(zhí)行了showNextMsg 方法
查看 showNextMsg 方法的實(shí)現(xiàn)
const initInstance = () => { instance = new MessageBoxConstructor({ el: document.createElement('div') }); instance.callback = defaultCallback; };
const showNextMsg = () => { // 首先對(duì) instance 進(jìn)行了判斷,如果沒(méi)有就 初始化一個(gè),初始化的方法 在上面;由此可見(jiàn),instance 是一個(gè)單例 if (!instance) { initInstance(); } instance.action = ''; // 判斷 instance 沒(méi)有顯示 或者 存在 closeTimer 的場(chǎng)景 if (!instance.visible || instance.closeTimer) { if (msgQueue.length > 0) { // 判斷了隊(duì)列長(zhǎng)度 currentMsg = msgQueue.shift(); // 移除隊(duì)列第一項(xiàng),拿到參數(shù)信息 let options = currentMsg.options; // 下面對(duì)參數(shù)一頓處理 for (let prop in options) { if (options.hasOwnProperty(prop)) {// 吧參數(shù) 復(fù)制給 instance instance[prop] = options[prop]; } } if (options.callback === undefined) { // 判斷有沒(méi)有 callback 沒(méi)有就使用 默認(rèn)的 callback instance.callback = defaultCallback; } let oldCb = instance.callback; // 從新對(duì) callback 進(jìn)行制定 instance.callback = (action, instance) => { oldCb(action, instance); showNextMsg(); // 進(jìn)行了遞歸調(diào)用,消耗隊(duì)列 }; // 判斷了 message 是不是 vnode 如果是 就使用默認(rèn)的 slot 渲染 .... if (isVNode(instance.message)) { instance.$slots.default = [instance.message]; instance.message = null; } else { delete instance.$slots.default; } // 繼續(xù)處理 參數(shù),如果 這些參數(shù)沒(méi)設(shè)置,就全部給他設(shè)置為 true ['modal', 'showClose', 'closeOnClickModal', 'closeOnPressEscape', 'closeOnHashChange'].forEach(prop => { if (instance[prop] === undefined) { instance[prop] = true; } }); // 吧這個(gè) el 掛載到 body 上面, 此時(shí)候的 el 還是隱藏的 document.body.appendChild(instance.$el); // 使用Vue 的nextTick 異步更新隊(duì)列,去設(shè)置 instance 的顯示 Vue.nextTick(() => { instance.visible = true; }); } } };
到這里基本就分析完了 他使用 Vue.nextTick 異步更新隊(duì)列 去設(shè)置了 instance.visible = true;
異步更新隊(duì)列 默認(rèn)使用了 Promise.then 微任務(wù) 去處理callback
所以 我們?cè)谘h(huán)中調(diào)用 $alert , 是在最后 微任務(wù)隊(duì)列清空的時(shí)候 去設(shè)置了 instance.visible = true;
so. 我們只看到最后一條提示。
故此 我們已經(jīng)基本知道了問(wèn)題的原因,那我對(duì)于我們的需求就立馬能想到了處理方案, 我們僅需吧 每一條消息 放到 宏任務(wù)隊(duì)列中去,即可:
那我們上代碼:
showMsg(){ for(let i = 0; i < 4; i++){ let timer = setTimeout(()=>{ this.$alert('show message !'+ i,'提示') clearTimeout(timer) timer = null }) } }
這樣就成功完成了需求所描述的功能 ...
非常的nice
DEMO演示
感受一下這個(gè) demo 吧
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>vue 基于element-ui 實(shí)現(xiàn) 按鈕組按需折疊功能</title> <link rel="stylesheet" rel="external nofollow" > </head> <body> <div id="app"> <h2>element-ui 中 alert 實(shí)現(xiàn)連續(xù)提示</h2> <el-button @click="showMsg1">DEMO1</el-button> 單個(gè)調(diào)用,提示一次 <hr/> <el-button @click="showMsg2">DEMO2</el-button> 循環(huán)4次,僅提示了最后一次 <hr/> <el-button @click="showMsg3">DEMO3</el-button> 循環(huán)4次,提示了每一次 <hr/> <el-button @click="showMsg4">DEMO4</el-button> 放入微任務(wù)隊(duì)列,僅提示最后一次 <hr/> <el-button @click="showMsg5">DEMO5</el-button> 放入宏任務(wù)隊(duì)列,提示每后一次 </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <script> new Vue({ el: '#app', methods: { showMsg1(){ this.$alert('show message !','提示') }, showMsg2(){ for(let i = 0; i < 4; i++){ this.$alert('show message !'+ i,'提示') } }, showMsg3(){ for(let i = 0; i < 4; i++){ let timer = setTimeout(()=>{ this.$alert('show message !'+ i,'提示') clearTimeout(timer) timer = null }) } }, showMsg4(){ for(let i = 0; i < 4; i++){ Promise.resolve().then(()=>{ this.$alert('show message !'+ i,'提示') }) } }, showMsg5(){ for(let i = 0; i < 4; i++){ let timer = setTimeout(()=>{ this.$alert('show message !'+ i,'提示') clearTimeout(timer) timer = null }) } }, }, }) </script> </html>
以上就是element ui循環(huán)調(diào)用this.$alert 消息提示只顯示最后一個(gè)的詳細(xì)內(nèi)容,更多關(guān)于element ui調(diào)用this.$alert 消息提示的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue修改swiper框架輪播圖小圓點(diǎn)的樣式不起作用的解決
這篇文章主要介紹了vue修改swiper框架輪播圖小圓點(diǎn)的樣式不起作用的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04vue+iview的菜單與頁(yè)簽的聯(lián)動(dòng)方式
這篇文章主要介紹了vue+iview的菜單與頁(yè)簽的聯(lián)動(dòng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07vue?動(dòng)態(tài)路由component?傳遞變量報(bào)錯(cuò)問(wèn)題解決
這篇文章主要為大家介紹了vue?動(dòng)態(tài)路由component?傳遞變量報(bào)錯(cuò)問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05vue實(shí)現(xiàn)echarts餅圖/柱狀圖點(diǎn)擊事件實(shí)例
echarts原生提供了相應(yīng)的API,只需要在配置好echarts之后綁定相應(yīng)的事件即可,下面這篇文章主要給大家介紹了關(guān)于vue實(shí)現(xiàn)echarts餅圖/柱狀圖點(diǎn)擊事件的相關(guān)資料,需要的朋友可以參考下2023-06-06使用vue-element-admin框架從后端動(dòng)態(tài)獲取菜單功能的實(shí)現(xiàn)
​ vue-element-admin是一個(gè)純前端的框架,左側(cè)菜單是根據(jù)路由生成的。實(shí)際開(kāi)發(fā)中經(jīng)常需要根據(jù)當(dāng)前登陸人員的信息從后端獲取菜單進(jìn)行展示,本文將詳細(xì)介紹如何實(shí)現(xiàn)該功能2021-04-04前端vue?a鏈接下載文件失敗的問(wèn)題(未發(fā)現(xiàn)文件)
這篇文章主要介紹了前端vue?a鏈接下載文件失敗的問(wèn)題(未發(fā)現(xiàn)文件),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09過(guò)濾器vue.filters的使用方法實(shí)現(xiàn)
這篇文章主要介紹了過(guò)濾器vue.filters的使用方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09Vue動(dòng)態(tài)數(shù)據(jù)實(shí)現(xiàn)?el-select?多級(jí)聯(lián)動(dòng)、數(shù)據(jù)回顯方式
這篇文章主要介紹了Vue動(dòng)態(tài)數(shù)據(jù)實(shí)現(xiàn)?el-select?多級(jí)聯(lián)動(dòng)、數(shù)據(jù)回顯方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07解讀vue項(xiàng)目中遇到的深拷貝淺拷貝問(wèn)題
這篇文章主要介紹了vue項(xiàng)目中遇到的深拷貝淺拷貝問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10VUE table表格動(dòng)態(tài)添加一列數(shù)據(jù),新增的這些數(shù)據(jù)不可以編輯(v-model綁定的數(shù)據(jù)不能實(shí)時(shí)更新)
這篇文章主要介紹了VUE table表格動(dòng)態(tài)添加一列數(shù)據(jù),新增的這些數(shù)據(jù)不可以編輯(v-model綁定的數(shù)據(jù)不能實(shí)時(shí)更新),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-04-04