Skip to content
本页目录

一、什么是EventBus

  • EventBus是一个开源库,利用发布/订阅者模式对项目进行解耦
  • 利用很少的代码来实现多组件间通信
  • 在Vue中可以使用它来作为沟通桥梁的概念,就像所有组件共用的相同的事件中心
  • 如图所示,可以向该中心注册发送事件或者接收事件,这也就说明了所有组件可以上下平行地通知其他组件 image.png

二、 在vue2 中如何使用eventBus

🌼 创建事件总线

  • 第一种方法是可以直接在main.js初始化,在vue的原型对象上定义$eventBus
javascript
//main.js
Vue.prototype.$eventBus = new Vue()

  • 第二种可以新建一个.js文件,在其中引入Vue并导出它的一个实例
javascript
//event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

实质上它算一个不具备DOM的组件,我们需要的仅仅是它的实例方法

🌼 引入event-bus.js

  • 仅使用上述第二种方法才需要这一步
  • 每一个使用到eventBus的组件都需要引入event-bus.js
javascript
import EventBus form './eventBus.js'

🌼触发事件

  • 发布者角色
  • 使用方法
javascript
//对于方式一
this.$eventBus.$emit('eventName',params....)
//对于方式二
EventBus.$emit('eventName',params....)

  • 使用实例 --在页面A发布事件
<template>
    <button @click="sendMsg()">-</button>
</template>
 
<script> 
import EventBus from './eventBus.js'
export default {
  methods: {
  //发送事件
    sendMsg() {
      EventBus.$emit("aPostMsg", '页面A发出的消息');
      //或者
      this.$eventBus.$emit('aPostMsg','页面A发出的消息');
    }
  }
}; 

🌼 监听事件

  • 订阅者角色
  • 使用方法
//对于方式一
this.$eventBus.$on('evnetName',(params...) => {
    //do something....
})
//对于方式二
EventBus.$on('eventName', (params...) => {
    //do something....
})

  • 使用实例 --在页面B订阅事件
<script> 
import EventBus from './eventBus.js'
export default {
  data(){
    return {}
  },
  mounted() {
    EventBus.$on("aPostMsg", (msg) => {
      console.log(msg) //页面A发出的消息
    });
    //或者
    this.$eventBus.$on("aPostMsg", (msg) => {
      console.log(msg) //页面A发出的消息
    });
  }
};

如果只是这样的,监听事件会一直存在,反复进入到接收组件内操作获取数据我们只期待发送一次,但是会发生多次

🌼 移除事件监听

  • 原因:

    • 避免在监听的时候,如上述所说的,事件被反复监听
    • 因为是热更新,事件可能会被多次绑定监听
    • 没有及时移除eventBus也可能会导致内容泄漏
  • 那么如何移除事件监听呢

    • 移除单个事件
    //对于方式一
    EventBus.$off('aPostMsg')
    //对于方式二
    this.$eventBus.$off('aPostMsg')
    
    
    • 移除所有事件
    //对于方式一
    EventBus.$off('aPostMsg')
    //对于方式二
    this.$eventBus.$off('aPostMsg')
    
    
  • 使用实例

    • 在beforeDestroyed(){}中监听移除事件
    beforeDestroyed(){
      EventBus.$off('aPostMsg')
      //或者
       this.$eventBus.$off('aPostMsg')
    }
    
    

三、vue3 中的 eventBus

🌷 Vue3的变化

  • 在 Vue3.0+ 的版本中,Vue 移除了$on$off$once方法;并且没有提供兼容的功能
  • 在vue3中推荐我们使用mitt事件总线传递数据,其实mitt的使用方式和vue原本的自定义事件使用方式相同 -详细可查看文档

🌷 mitt的使用

- 在根目录终端执行
```js
npm install --save mitt
```
- 将方法导出使用
```js 
// eventBus.js
import emitter from 'tiny-emitter/instance'

export default {
  $on: (...args) => emitter.on(...args),
  $once: (...args) => emitter.once(...args),
  $off: (...args) => emitter.off(...args),
  $emit: (...args) => emitter.emit(...args),
}
```

四、 手写 eventBus

🌻 实现思路:

  • 声明了一个EventBus类,用来处理发布订阅,用events对象存储监听的时间, 用数组存储监听事件的回调函数
  • 订阅 了事件thing1,thing2.... 先判断该事件是否存储过,如果没有存储过就赋值为空数组,存储过就往数组里面push回调函数
  • 触发了事件,则从events取出该事件的回调函数数组,利用for..of..对其进行遍历调用
  • 移除事件 ,如果events有该事件的话则对其进行delete

🌻 实现代码

  class EventBus {
    constructor() {
      this.events = {}; // 用于存储所有订阅事件
    }
    // 订阅事件
    $on(name, callbcak) {
      // 判断是否存储过
      if(!this.events[name]) {
        this.events[name] = [];
      }
      this.events[name].push(callbcak); // 往事件数组里面push
    }
    // 发布事件
    $emit(name, ...args) {
      // 获取存储的事件回调函数数组
      const eventList = this.events[name];
      // 执行所有回调函数
      for (const callbcak of eventList) {
        callbcak(...args);
      }
    }
    // 移除事件
    $off(name) {
    if(this.evetns[name]) {
        delete this.events[name]
    }