Vue-EventBus

x33g5p2x  于2022-07-14 转载在 其他  
字(3.0k)|赞(0)|评价(0)|浏览(316)

前沿

vue组件非常常见的有父子组件通信,兄弟组件通信。而父子组件通信就很简单,父组件会通过 props 向下传数据给子组件,当子组件有事情要告诉父组件时会通过 $emit 事件告诉父组件。如果1个页面里很多组件没有任何引入和被引入关系(不是父子关系),而他们大多都是同级关系,该如何通信?

听说EventBus,或者说或多或少都了解过,他可以在任何两个组件中进行传值,不局限于父子、祖孙或是兄弟组件,也可以说他是一种发布——订阅的设计模式。

注意:

  1. 只能在一个页面里会初始化的组件之间才能通信, 因为只有组件初始化后,他们之间才能看见对方,才能加载到EventBus里
  2. 如果组件销毁后那么EventBus是无法操作销毁后组件内的信息 ,所以发布事件的组件一定要在监听事件的组件之后结束生命周期(被销毁),否则发布的时候就会报错,
  3. 发布事件的时候,所对应的监听事件的组件必须存在并且已经初始化了

以上这些问题需要在开发的时候注意, 绝大部分场景基本不会出现上面的问题,所以放心使用,如果出现了那么就,依据我上面说的情况进行分析就能解决了

EventBus的简介

EventBus 又称为事件总线。在Vue中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。

创建

Vue中自带EventBus,不需要额外任何使用插件 ,只需要new一个「vue实例」像这样~
创建一个EventBus.js文件

import Vue from 'vue' // 引入vue

const EventBus = new Vue() // 创建实例

export default EventBus // 导出

引入

引入的方式有两种 ,任选其一 建议使用import方式

使用import引入

import EventBus from '../EventBus'

使用Vue原型链引入

// 在 src 的 main.js 中,加上以下代码 
// 引入第一步创建好的 EventBus
import EventBus from './EventBus'
// 这个方式可以在任何组件里直接用 this.$EventBus 调用
Vue.prototype.$EventBus = EventBus

// 也可以直接这样使用,不需要第一步的创建
// import Vue from 'vue'
// Vue.prototype.$EventBus = new Vue()

// 这种也行 但是使用的时候需要windows.eventBus 调用
//window.eventBus = new Vue();

下面教程我们就使用import方式引入的方式来演示

监听事件

语法:

// eventName 是事件的名称  , param接收的参数
EventBus .$on('eventName', (param1,param2,...)=>{
        //需要执行 逻辑代码
}

发布事件

语法: EventBus .$emit('eventName', param1,param2,...)

  • eventName 发布事件的名称, 要和监听事件的名称一致
  • param给监听事件的方法传参

使用案例

我们在A组件面里, 将消息发给B组件

<!-- A.vue -->
<template>
    <button @click="sendMsg()">-</button>
</template>

<script> 
import { EventBus } from "../event-bus.js";
export default {
  methods: {
    sendMsg() {
      EventBus.$emit("aMsg", '来自A页面的消息');
    }
  }
}; 
</script>
<!-- B.vue -->
<template>
  <p>{{msg}}</p>
</template>

<script> 
import {  EventBus } from "../event-bus.js";
export default {
  data(){
    return {
      msg: ''
    }
  },
  mounted() { //组件初始时候加载
    EventBus.$on("aMsg", (msg) => {
      // A发送来的消息
      this.msg = msg;
    });
  }
};
</script>

同理我们也可以在 B组件 向 A组件 发送消息或者操作A组件方法等…

移除事件

在开发的过程中,我们要及时移除不使用的 eventBus ,原因:
① 为了避免在监听时,事件被反复触发
② 由于热更新,事件可能会被多次绑定监听,这时也需要移除事件监听
③ 未及时移除的 eventBus 会导致内存泄漏

语法: eventBus.$off('eventName');

//当前实例销毁之前调用
 beforeDestroy () {
    console.log('----A页面销毁监听事件----')
    this.$EventBus.$off('getNum')
}

EventBus的原理是什么?

废话少说,直接上代码,用 class 来实现我们自己的 EventBus:

class MyEventBus {
    constructor() {
        // 存储所有事件对应的回调的对应关系
        /**
         * key : [ callback, callback ]
         */
 
        this.items = {};
    }
 
    // 监听
    $on(eventName, callback) {
        if (!this.items[eventName]) {
            //一个事件可能有多个监听者
            this.items[eventName] = [];
        }
        this.items[eventName].push(callback)
 
        // 简化版写法 等同于上面
        // (this.items[eventName] ||= []).push(callback)
    }
 
 
    // 触发监听
    $emit(eventName, ...args) {
        if (!this.items[eventName]) return;
        this.items[eventName].forEach(ca => ca(...args))
    }
 
 
    // 去掉监听
    $off(eventName) {
        this.items[eventName] = []
    }
}
 
export default new MyEventBus();

总结

就是我们在项目中可能会创建多个 eventBus.js 文件,而两个或者多个组件要使用 eventBus 进行通信时一定要使用同一个 eventBus.js 文件,否则会报错,我之前就遇到过,哈哈!

Vue中使用 eventBus 实现组件间的通信时,需要对 Bus.$emit()Bus.$on()Bus.$off() 或者其他 API 搭配使用。结合当前环境,判断是否有干扰项从而决定是否对 eventBus 进行移除。 因为如果移除了,其他组件还在调用那么就悲剧了, 所以一定要分析好在哪里移除

点赞 -收藏-关注-便于以后复习和收到最新内容有其他问题在评论区讨论-或者私信我-收到会在第一时间回复感谢,配合,希望我的努力对你有帮助^_^免责声明:本文部分素材来源于网络,版权归原创者所有,如存在文章/图片/音视频等使用不当的情况,请随时私信联系我。

相关文章