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() 方法来解决。

  大致解决方法就是这样,可能解释的不是太清楚,自己可以写个案例实现下应该可以帮助理解。最后对 eventBus 的使用做一个小的补充,就是我们在项目中可能会创建多个 eventBus.js 文件,而两个或者多个组件要使用 eventBus 进行通信时一定要使用同一个 eventBus.js 文件,否则会报错,我之前就遇到过,哈哈!

  总结:Vue中使用 eventBus 实现组件间的通信时,需要对 Bus.$emit()Bus.$on()Bus.$off() 或者其他 API 搭配使用。结合当前环境,判断是否有干扰项从而决定是否对 eventBus 进行移除。

 

 

 

 

 

 

posted @ 2020-07-13 13:46  黑夜丶vn  阅读(3703)  评论(1编辑  收藏  举报
Live2D