1. 程式人生 > 實用技巧 >Vue元件通訊中事件匯流排(eventBus)的使用

Vue元件通訊中事件匯流排(eventBus)的使用

  之前公司的專案中使用 eventBus 進行元件通訊時遇到了一些資料渲染時的問題,下面對遇到的這些問題做下簡單的介紹以及解決方法。

  我們都知道,在 Vue 中,元件通訊的方式有很多,而針對那些沒有父子級關係或者任何關係的元件要實現通訊(資料傳遞)的方法就是使用 Vuex 或者 eventBus(事件匯流排),具體應該選擇哪一種還要看實際情況。公司的專案中兩種方法都有使用,而自己當時對 Vuex 的使用還不是很熟悉,所以就選擇了 eventBus 來實現元件通訊。然而在開發過程中還是遇到了一些問題。

  首先來看下專案中要實現的效果:

  大致需求是這樣:左邊地圖元件和右邊檢視元件需要關聯,點選左邊時需要傳送 機器告警(圖)的資料

機器缺陷(圖)的資料 給檢視元件,而,右邊檢視元件中有一個公共的元件用來展示資料,使用者通過點選 “機器告警” 或者 “機器缺陷” 按鈕來獲得對應的圖示。

  robotState.vue 中的 html 程式碼(部分):

 1 <template>
 2   <div>
 3     <section class="the-wrapper">
 4       <h2 class="title">
 5         <span @click="switchView" :class
="xxxx"></span> 6 <span class="switch-btn" :class="{ active: currentTab === 1 }" @click="switchTab(1)">機器告警</span> 7 <span class="switch-btn" :class="{ active: currentTab === 2 }" @click="switchTab(2)">機器缺陷</span> 8 </h2> 9 </section
> 10 <!-- 機器告警圖(表) --> 11 <section v-if="currentTab === 1" :key="0" style="xxxx"> 12 <transition enter-active-class="animated slideInLeft"> 13 <v-canvas-pie v-if="isPieView" ref="pie" /> 14 <v-table v-else ref="table" /> 15 </transition> 16 </section> 17 <!-- 機器缺陷圖(表) --> 18 <section v-if="currentTab === 2" :key="1" style="xxxx"> 19 <transition enter-active-class="animated slideInLeft"> 20 <v-canvas-pie v-if="isPieView" ref="pie" /> 21 <v-table v-else ref="table" /> 22 </transition> 23 </section> 24 </div> 25 </template>

  map.js 中的邏輯(部分):

 1 getData = async (city) => {
 2     // 機器告警(圖)
 3     axios.post('xxxxxxxxxxxxx',{id:city.code})
 4         .then(res=>{
 5            res.data.map(item=>{
 6                Bus.$emit('AlarmInfoPie',[
 7                 { name:"正常",value:item.normal },
 8                 { name:"一般",value:item.commonly },
 9                 { name:"嚴重",value:item.serious },
10                 { name:"危急",value:item.critical },
11                ])
12            }) 
13         })
14 
15     // 機器缺陷(圖)
16     axios.post('mmmmmmmmmmmmmmm',{id:city.code})
17     .then(res=>{
18         res.data.map(item=>{
19             Bus.$emit('defectPie',[
20              { name:"無缺陷",value:item.normal },
21              { name:"一般缺陷",value:item.commonly },
22              { name:"嚴重缺陷",value:item.serious },
23              { name:"危急缺陷",value:item.critical },
24             ])
25         }) 
26     })
27 }

  robotState.vue 中的邏輯(部分):

 1 export default {
 2     components:{
 3         VCanvasPie,
 4         VTable
 5     },
 6     data(){
 7         return {
 8             isPieView:true,
 9             currentTab:1,
10         }
11     },
12     methods: {
13         // 機器告警(圖)
14         async getRobotAlarmPie(){ 
15             let temp,       // 定義需要渲染的資料
16             const result = await axios.get('xxxxxxxxxxxxxxxx')
17             result.data.map(item=>{
18                 // 資料處理(省略)
19                 this.$refs.pie.init(temp)
20             })
21             // 渲染從 map.js 傳過來的資料
22             Bus.$on('AlarmInfoPie',(data)=>{
23                 temp = data
24             })
25             this.$refs.pie.init(temp)
26         },
27          // 機器缺陷(圖)
28         async getRobotDefectPie(){
29             let temp,   // 定義需要渲染的資料
30             const result = await axios.get('xxxxxxxxxxxxxxxx')
31             result.data.map(item=>{
32                 // 資料處理(省略)
33                 this.$refs.pie.init(temp)
34             })
35             // 渲染從 map.js 傳過來的資料
36             Bus.$on('defectPie',(data)=>{
37                 temp = data
38             })
39             this.$refs.pie.init(temp)
40         }
41     },
42 };

  一開始資料處理邏輯就是這樣,結果卻是:點選地圖元件的某個區域時,會進行正常渲染 “機器告警” 的資料,如果點選 “機器缺陷” 時,再點選地圖元件的當前區域時卻得不到對應的資料,而是渲染的是 “機器告警” 的資料,當時很懵逼,最後才知道由於 右邊檢視元件共用了一個數據展示的元件,當點選地圖某個區域時,map.js 中的 eventBus 會有兩個事件發射,robotState.vue 中對應也就有兩個事件監聽,從而獲取資料,無論是點選 “機器缺陷” 還是 “機器告警”,後面監聽的事件得到的資料都會被覆蓋。找到了問題原因就很好解決,最先想到的是使用 vuex 來解決,但是需要推翻以前的程式碼重寫,因為專案中有很多資料展示,就很麻煩;然後想的是能不能使用 eventBus 中的方法來解決,最後找到了 eventBus.$off() 方法來解決。