Vue2.0 探索之路——元件複用重複響應的研究

城南發表於2017-08-22

前言

前段時間,同事發現一個彈窗元件被多個頁面複用,然後點選按鈕出現了多次響應。明明頁面都會被銷燬掉的呀,為啥還會出現重複呼叫呢。

其實以前我也碰到過一兩次,不知道啥情況後來沒有再復現,再加上工期緊,當時就沒有引起重視。這次同事碰到了,多次試驗復現了。才深知當時挖的大坑啊沒有填。

所以這次就單獨弄了個demo專門復現並解決這個問題。也希望吸取教訓,以後碰到問題都要記錄下來,儘早早早早早解決啊,不然都是坑。

另外,文章裡針對父子元件的全域性事件監聽是錯誤的選擇,請大家不要使用這種。(但是對於兄弟元件的事件響應監聽是可以用全域性的,所以本文適合於這種情況)。
請用官方例子(遇到問題,請多用官方,不然直接參考其他同學的思路很可能挖坑。這裡是以前直接搜尋到eventbus的實現方式,請引以為戒,哈哈,我就做個反面教材吧)

傳送門:cn.vuejs.org/v2/guide/co…

重複響應程式碼示例

首先我寫了一個dialogx的小元件,裡面只有一個點選按鈕。當點選的時候,會觸發一個btnClick的事件。

然後我又寫了兩個頁面用來測試重複響應。下面是 test1.vue,至於test2也一樣,就不重新放圖了。

然後,我們們來點點點點點點!就能發現,在test2頁面發起的事件,而test1也響應了,這屬於重複響應是不符合我們的專案需要的。

這...是咋回事~~??

經過查詢相關資料,確定了問題在於沒有過去的銷燬事件響應

好,我們出發去加上銷燬邏輯。

加入銷燬操作

於是我在dialogx.vue中加入以下程式碼,在路由切換元件被銷燬的時候,對btnClick事件進行銷燬。順便列印一下 this.$root看看裡面是個啥結構。

然後就有了以下的操作,居然...居然 test2.vue 沒法響應了。WTF,這又是啥情況。

冷靜下來,好好分析。首先這種情況是因為我們加了銷燬操作導致的,所以肯定是銷燬的問題。
那麼我們繼續追蹤。發現路由切換的各種操作的順序是這樣的。

這說明 什麼問題?

新頁面的created先執行,然後開始逐漸銷燬老頁面。仔細看看,我們能發現問題,test2.vue在建立監聽事件的時候,是在dialogx.vue銷燬之前的。人家剛建立好監聽事件,由於執行順序問題,被子元件給清除了,所以 test2.vue在點選發射時,是攔截不到的。
好,既然因為執行順序的問題,那我們把監聽事件註冊放在 mounted裡。

果然,成功了。

再探索一下

對於事件的觸發和監聽,因為我們這是用 eventbus實現的。為了看看裡面具體是為什麼,於是我列印了 this.$root看看更細節的是為什麼。

首先,每一次監聽 this.$root.$on('btnClick')都是一次事件註冊,然後我在列印的結果裡,找到了以下內容。

btnClick 是一個陣列,這就意味著每一次btnClick事件註冊,都是往裡存一個處理方法。
然後為了驗證我的想法,我把 test2.vue中的監聽事件去了,直接看我們的 $off效果。

null,這就解釋了為什麼,剛才監聽事件寫在 created裡,為什麼不生效了,因為整個事件都被設定為 null了。

總結

為了達到元件複用不產生重複響應的問題。我們可以如下做。

1.在子元件裡的destroyed方法裡,對事件進行銷燬操作($off)
2.在頁面中 mounted方法中進行事件監聽。

GitHub程式碼地址:github.com/XuXiaoGH/vu…

寫在最後

這次是一次異常排查過程的記錄,如果對你有些許幫助,不妨點個喜歡,這將是我繼續的很大動力。

ps: GIF截圖軟體是 LICEcap ,非常好用,推薦一下。

相關文章