一、eventBus的介绍
EventBus
又称为事件总线。在Vue中可以使用 EventBus
来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”,因此需要Pinia
或Vuex
作为状态管理中心,将通知的概念上升到共享状态层次。
想先看关键点可跳转到三、注意
二、使用
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>
三、注意
$bus.$on
对同一事件可绑定多次监听器,信息触发时全都会执行一次;$bus.$off
有两个参数和一个参数的用法另一个实验demo (
test
为true和false对应下面的第2小点中的两种情况,即是否绑定的是同一个函数方法作为监听器)使用
$bus.$off(event, fn)
**方法解绑监听器对匿名函数fn
是无效的;没有函数名,也无法获得之前已绑定的匿名函数监听器fn0的对象引用,使用
eventBus
自然找不到指定的监听器去进行解绑操作$bus.$off(event, fn)
方法移除指定事件的一个**指定的函数方法监听器; (这个监听器函数方法必须与之前使用$bus.$on
绑定的监听器函数对象是同一个对象,否则找不到指定的监听器函数,也就无法移除任何监听器了,这时情况就类似于尝试解绑匿名函数监听器了)$bus.$off(event)
方法移除指定事件名的所有监听器
尽量保证
$bus.$on
与$bus.$off
成双成对 推荐使用钩子函数
mounted
与beforeDestory
, 即在页面初始化完成后进行事件订阅,并在页面销毁时(前)取消相应事件订阅。以此保证eventBus
的纯洁,否则再次进入这个页面时,eventBus
还带有上次绑定的监听器,如果你再次绑定一次监听器的话,那么当信号触发时,这个事件就会重复执行。$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 }})
Vue2 与 Vue3关于eventBus的区别
Vue2 eventBus
的具体使用方法可查阅官方文档 Vue2实例方法$on、$once、$off、$emit另外需注意的是, Vue3中移除了
$on
,$off
及$once
, 只剩下$emit
用于对父组件传递信息Vue3
中想使用eventBus
可以借助第三方库如vue3-eventbus
等, 或者自己实现
四、结语
在项目中使用全局的事件总线eventBus
可以帮助我们即使在不同页面中也可传递信息,可以说是非常方便的。
只要注意上面说的几点,劈开雷区,就可以愉快的使用了。