Vue EventBus事件总线的使用及注意事项


一、eventBus的介绍

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

​ 想先看关键点可跳转到三、注意

二、使用

1. 初始化

​ Vue已经帮助我们准备了很多,我们只需新建一个Vue实例当作**全局的eventBus即可。可以如下在main.js中引入。

/**
 * 添加事件总线
 * @param {*} Vue
 */
var EventBus = new Vue();
Object.defineProperties(Vue.prototype, {
  $bus: {
    get: function () {
      return EventBus;
    }
  }
});

// 之后在所有的Vue组件中即可访问到事件总线eventBus了,如下

js代码中, 即可通过 this.$bus 访问到事件总线eventBus了

<script>
	this.$bus.$emit('event'); // 通过eventBus发出事件信号'event'
</script>

template块中直接使用 $bus 也可以访问到

<template>
	<button @click="$bus.$emit('event')">Click</button>
</template>

2. 订阅&发布&取消订阅

四个方法

​ 在我们的事件总线中主要使用$on$emit来进行事件的订阅及发布, 使用$off取消订阅,还有$once用于一次性的订阅 官方文档 | Vue2实例方法$on、$once、$off、$emit

  • $on用来订阅某个信息,也可以理解为添加监听器;
  • $once用来添加一个一次性的监听器,触发一次即失效了;
  • $emit用来发布信息,或者说发出信号;
  • 之后也会讲到$off是用来取消信息订阅,或者说移除监听器的。

示例

​ 代码如下:(可查看在线演示demo, 代码见https://github.com/hjwforever/eventbus-vue2)

Template
<template>
  <div class="hello">
    <span>num: {{ num }}</span
    ><br />
    <span>count: {{ count }}</span
    ><br /><br />
    <button @click="on">Subscribe One</button><br /><br />
    <button @click="off">UnSubscribe One</button><br /><br />
    <button @click="offAll">UnSubscribe All</button><br /><br />
    <button @click="emit">Click Me 1</button> =
    <button @click="$bus.$emit('event')">Click Me 2</button><br />
  </div>
</template>
JS
<script>
export default {
  name: "EventBusDemo",
  data() {
    return {
      num: 1, // 申明变量
      count: 0, // 统计事件订阅的方法数目
    };
  },
  // 页面初始化后, 进行一次事件订阅
  mounted() {
    this.on();
  },
  // 页面销毁前取消订阅,否则有时候可能会导致订阅多次而没有取消订阅,最终一个方法执行多次
  beforeDestory() {
    this.off(); // 一般不会使用offAll吧,有点暴力hh, 注意不要随意订事件阅即可
  },
  methods: {
    // 定义函数方法
    // data为$emit传递的参数
    // 使用callback(arg)可以将arg作为参数返回给$on的回调函数(使用且仅使用最早callback的那个参数arg)
    myEvent(data, callback) {
      this.num++;
      console.log("$emit data", data);
      console.log("num = ", this.num);
      callback(this.num);
    },
    // 对事件添加一次订阅, 即添加一个监听器
    on() {
      // 通过eventBus订阅事件'event'绑定一个'myEvent'方法, 即添加一个监听器
      // 注意,同一方法可添加多次,并且如果没有被取消订阅的话,信息触发时全都会被一一执行
      this.$bus.$on("event", this.myEvent);
      // 统计数加一
      this.count++;
      console.log("count = ", this.count);
    },
    // 取消事件的一次订阅, 即移除一个监听器
    off() {
      // 取消对事件'event'的一个名为'myEvent'方法的订阅
      // 注意, 如果已经添加了多次,则只可取消一次,即$off这种双参数用法只可移除一个监听器
      this.$bus.$off("event", this.myEvent);
      // 统计数减一
      this.count--;
      console.log("count = ", this.count);
    },
    // 取消事件的所有订阅, 即移除所有监听器
    offAll() {
      // 取消对事件'event'的所有订阅
      // 即$off这种一个参数的用法, 只可移除指定事件名的所有监听器
      this.$bus.$off("event");
      // 统计数归零
      this.count = 0;
      console.log("count = ", this.count);
    },
    // 发送事件信号
    emit() {
      // 通过eventBus发出事件信号'event', 传递参数, 并定义回调函数(其参数为$on 第一个callback回来的值)
      this.$bus.$emit("event", this.num, (res) => { // 回调函数
        console.log("[event callback]: res", res);
      });
    },
  },
};
</script>

三、注意

  1. $bus.$on对同一事件可绑定多次监听器,信息触发时全都会执行一次;

  2. $bus.$off两个参数一个参数的用法

    另一个实验demo (test为true和false对应下面的第2小点中的两种情况,即是否绑定的是同一个函数方法作为监听器)

    1. 使用$bus.$off(event, fn) **方法解绑监听器对 匿名函数fn是无效的;

      没有函数名,也无法获得之前已绑定的匿名函数监听器fn0的对象引用,使用eventBus自然找不到指定的监听器去进行解绑操作

    2. $bus.$off(event, fn) 方法移除指定事件的一个**指定的函数方法监听器; (这个监听器函数方法必须与之前使用$bus.$on绑定的监听器函数对象是同一个对象,否则找不到指定的监听器函数,也就无法移除任何监听器了,这时情况就类似于尝试解绑匿名函数监听器了)

    3. $bus.$off(event)方法移除指定事件名的所有监听器

  3. 尽量保证$bus.$on$bus.$off成双成对

    ​ 推荐使用钩子函数mountedbeforeDestory, 即在页面初始化完成后进行事件订阅,并在页面销毁时(前)取消相应事件订阅。以此保证eventBus的纯洁,否则再次进入这个页面时,eventBus还带有上次绑定的监听器,如果你再次绑定一次监听器的话,那么当信号触发时,这个事件就会重复执行

  4. $bus.$on(event, fn, callback) 方法具有三个参数

    • 第一个参数是事件名

    • 第二个参数是绑定的监听器函数方法

    • 第三个参数是回调函数,例子如下

      function myEvent()
      this.$bus.$on("event", this.myEvent, ({ event, data }) => {
      	console.log("[event callback]: EventName", event, " data", data);
      });
      this.$bus.$emit('event', { event: 'something', data: { num: this.num }})
      
  5. Vue2 与 Vue3关于eventBus的区别

    Vue2 eventBus的具体使用方法可查阅官方文档 Vue2实例方法$on、$once、$off、$emit

    另外需注意的是, Vue3中移除了 $on, $off$once, 只剩下 $emit 用于对父组件传递信息

    Vue3中想使用eventBus可以借助第三方库vue3-eventbus等, 或者自己实现

四、结语

​ 在项目中使用全局的事件总线eventBus可以帮助我们即使在不同页面中也可传递信息,可以说是非常方便的。

​ 只要注意上面说的几点,劈开雷区,就可以愉快的使用了。

参考

https://github.com/hjwforever/eventbus-vue2

在线演示demo

另一个实验demo

Vue实例方法$on、$once、$off、$emit

https://zhuanlan.zhihu.com/p/72777951


文章作者: hjwforever
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hjwforever !
评论
  目录