關於element-ui 中使用Notice元件(Message、MessageBox、Notification)所遇到的坑

林凡同學發表於2019-03-04

今天在全域性使用Message元件的時候(單獨使用import Message from `element-ui`),發現第一次開啟Message後再開啟的Message無法關閉了,無論是使用showClose手動關閉還是通過duration來自動關閉,在第二次開啟對應的元件的時候都無法關閉了,然而控制檯也都沒有報錯

這裡寫圖片描述

我的程式碼寫法如下:

import { Message } from `element-ui`

const message_conf = {
	showClose: true,
	message: `網路出錯啦...`,
	type: `error`,
	duration: 2000
}

//... some fn doing
Message(message_conf)

複製程式碼

根據官網給出的demo:

this.$message({
    message: `居中的文字`,
    center: true
});


單獨引入 Message:

import { Message } from `element-ui`;
此時呼叫方法為 Message(options)。我們也為每個 type 定義了各自的方法,如 Message.success(options)。 並且可以呼叫 Message.closeAll() 手動關閉所有例項。
複製程式碼

就是說可以在vm例項中通過this.$message(options)方法來呼叫出message,也可以通過在檔案中單獨引入Message,通過Message(options)來呼叫,而傳入的options的配置都是相同的,因為我是在一個公用的server方法中寫的Message,所以我想我是否可以放在vm例項中呼叫試一下呢,執行後發現,還是他麼的不能關閉…
what the mother fucker???

這裡寫圖片描述

然後我再仔細看了一遍官網的呼叫:

this.$message({
    message: `居中的文字`,
    center: true
});
複製程式碼

他傳入的options是一個新的object, 而我第二次傳入的和第一次傳入的options都是同一個物件——message_conf,會不會是這個問題呢。然後我嘗試了一下把傳入的message_conf改成和官網一樣的

Message({
    showClose: true,
	message: `網路出錯啦...`,
	type: `error`,
	duration: 2000
})
複製程式碼

果然這樣就他麼不會出么蛾子了。。

然後我在第一次呼叫Message後,console.log了一下傳入的message_conf,果然,值他麼改變了:

這裡寫圖片描述

不要問我為啥const 修飾的物件為啥會改變,因為const 修飾引用型別的資料 都是修飾的是他的引用而不是實際對應的屬性值。

就意味著,第一次呼叫Message的時候將傳入的message_conf的值改變了,然後第二次傳入的message_conf就是第一次被修改後的值,那麼問題就一定是出在傳入的值上。
經過我嘔心瀝血的測試(其實就那麼一兩分鐘),發現導致無法關閉的關鍵屬性是closed,第一次呼叫Message後傳入的message_conf多了一個屬性closed:true,再第二次傳入的時候將這個屬性傳入的話 那麼無論如何都無法關閉了。

我猜想的話,element-ui notice元件判定是否關閉就是通過傳入的closed來判定的,第一次傳入的option不包含這個屬性,那麼內建會通過Object.assign新增一個closed: false的屬性到傳入的物件中,然後在timer時間到或者執行close()方法的時候將 closed屬性變為true。

如果要用和我同樣的寫法的話解決方法就是講傳入的message_conf進行deepClone一次就好啦


本文研究的還不算深入,只是單純的解決了一下遇到同樣問題的童鞋,也淺談了一下原理。有興趣的同學可以自行看看原始碼~~

逼就裝到這裡了,告辭~

這裡寫圖片描述

相關文章