使用$on订阅事件
使用$emit发布事件
$emit发布事件可以传参
实现$off取消订阅
实现$once执行一次
<script>
class EventBus {
// 定义所有事件列表,此时需要修改格式:
// // {
// key: {
// D+id: Function,
// id: Function
// },
// key: Object,
// }
// Array存储的是注册的回调函数
constructor() {
this.eventObj = {}; // 用于存储所有订阅事件
this.callbcakId = 0; // 每个函数的ID
}
// 订阅事件,类似监听事件$on('key',()=>{})
$on(name, callbcak) {
// 判断是否存储过
if (!this.eventObj[name]) {
this.eventObj[name] = {};
}
// 定义当前回调函数id
const id = this.callbcakId++;
this.eventObj[name][id] = callbcak; // 以键值对的形式存储回调函数
return id; // 将id返回出去,可以利用该id取消订阅
}
// 发布事件,类似于触发事件$emit('key')
$emit(name, ...args) {
// 获取存储的事件回调函数数组
const eventList = this.eventObj[name];
// 执行所有回调函数且传入参数
for (const id in eventList) {
eventList[id](...args);
// 如果是订阅一次,则删除
if(id.indexOf('D') !== -1) {
delete eventList[id];
}
}
}
// 取消订阅函数,类似于$off('key1', id)
$off(name, id) {
console.log(this.eventObj)
// 删除存储在事件列表中的该事件
delete this.eventObj[name][id];
console.info(`${id}id事件已被取消订阅`)
// 如果这是最后一个订阅者,则删除整个对象
if (!Object.keys(this.eventObj[name]).length) {
delete this.eventObj[name];
}
}
// 订阅事件,只会执行一次,为了方便,id上直接加上一个标识d
$once(name, callbcak){
// 判断是否存储过
if (!this.eventObj[name]) {
this.eventObj[name] = {};
}
// 定义当前回调函数id,添加D则代表只执行一次
const id = "D" + this.callbcakId++;
this.eventObj[name][id] = callbcak; // 以键值对的形式存储回调函数
return id; // 将id返回出去,可以利用该id取消订阅
}
}
// 初始化EventBus
let EB = new EventBus();
// 订阅事件
EB.$on('key1', (name, age) => {
console.info("我是订阅事件A:", name, age);
})
EB.$once("key1", (name, age) => {
console.info("我是订阅事件B:", name, age);
})
EB.$on("key2", (name) => {
console.info("我是订阅事件C:", name);
})
// 发布事件key1
EB.$emit('key1', "小猪课堂", 26);
console.info("在触发一次key1")
EB.$emit('key1', "小猪课堂", 26);
// 发布事件
EB.$emit('key2', "小猪课堂");
</script>
本篇文章实现了一个较为简单的EventBus,但是也基本满足我们在项目中的使用了。想要实现EventBus,我们首要理解的就是发布订阅模式,然后我们在思考下面几个问题,基本上就能实现一个属于自己的EventBus了。
订阅事件如何存储?
如何传递参数?
如何给每个订阅事件添加唯一标识?
如何正确删除存储的订阅事件?
$on和$emit主要担任的是什么角色?
什么时发布订阅模式?
想明白了上面的问题那么EventBus我相信你也明白了,能够自己实现了。