1.实现Bus类
//自定义中央事件总线(Vue中是默认已经实现了$bus的功能)---下面的实现我是从Vue双向数据绑定底层原理那受到了启发
class Bus {
constructor() {
this.callbacks = {}; //存放事件,每个事件属性又都是一个对象,存放当前事件的所有回调
this.callbackEventId = 0; //每次自增
}
$on(name, fn) {
this.callbacks[name] = this.callbacks[name] || {};
this.callbacks[name][++this.callbackEventId] = fn;
return this.callbackEventId;
}
$emit(name, ...args) {
for (let id in this.callbacks[name]) {
this.callbacks[name][id](...args);
}
}
$off(name, id = undefined) {
if (id == undefined) {
// 如果只提供了name参数,则只会移除该事件相关的监听器;
delete this.callbacks[name];
} else {
// 如果同时提供了name和id 参数,则只会移除指定事件及回调函数的监听器。
delete this.callbacks[name][id];
if (Object.keys(this.callbacks[name]).length == 0) {
delete this.callbacks[name];
}
}
}
//清空所有的监听器
$offs() {
this.callbacks = {};
}
}
2.测试一下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>测试发布订阅模式</title>
</head>
<body>
<button onclick="publishEvent1()">发布事件1</button>
<button onclick="publishEvent2()">发布事件2</button>
<button onclick="closeEventA()">关闭A</button>
<button onclick="closeEventB()">关闭B</button>
<button onclick="closeEventC()">关闭C</button>
<button onclick="closeEventD()">关闭D</button>
<button onclick="closeEventAll()">关闭all</button>
<button onclick="subscribeEvents()">给A、B、C、D订阅事件</button>
<script src="./bus.js"></script>
<script>
// 使用示例
const bus = new Bus();
function subscribeEvents() {
// 订阅事件
let eventA = bus.$on("myEvent1", (data) => {
console.log("a订阅的事件1被触发了:", data);
});
let eventB = bus.$on("myEvent1", (data) => {
console.log("b订阅的事件1被触发了:", data);
});
let eventC = bus.$on("myEvent2", (data) => {
console.log("c订阅的事件2被触发了:", data);
});
let eventD = bus.$on("myEvent2", (data) => {
console.log("d订阅的事件2被触发了:", data);
});
}
subscribeEvents();
function publishEvent1() {
// 发布事件
bus.$emit("myEvent1", "hello1!");
}
function publishEvent2() {
// 发布事件
bus.$emit("myEvent2", "hello2!");
}
function closeEventA() {
bus.$off("myEvent1", eventA);
}
function closeEventB() {
bus.$off("myEvent1", eventB);
}
function closeEventC() {
bus.$off("myEvent2", eventC);
}
function closeEventD() {
bus.$off("myEvent2", eventD);
}
function closeEventAll() {
bus.$offs();
}
</script>
</body>
</html>
界面如下:
点击按钮发布事件1
:
点击按钮发布事件2
:
点击按钮关闭all
,然后再点击按钮发布事件1
,这时候控制台没有输出。点击给A、B、C、D订阅事件
,然后再点击按钮发布事件1
: