Vue中的组件传参是日常开发中常遇到的需求,其中EventBus
事件总线就是其中非常好用的一种,之前其实是比较排斥这种用法的,就是因为用的少,不了解所以出于对未知事物的恐惧,比较排斥。最近刷到一篇手写EventBus
的文章,看完才明白其中的大概原理,今天就以我自己的理解来给大家讲讲基本实现。
我们可以把EventBus
简单理解为一个公众号,其中公众号作者拥有发布($emit
)消息的能力,用户拥有订阅($on
)公众号的能力,公众号作者发布文章后,用户会收到文章内容推送,如果用户不喜欢推送的文章则可以选择取消订阅($off
)公众号的能力。接下来我们就来简单实现一下这些功能。
function EventBus() {
this.eventObj = {}; // 定义事件存储列表
this.callbackId = 0; // 定义事件id 可以理解为公众号订阅者人数
}
// 订阅
EventBus.prototype.$on = function(key, callback) {
if (this.eventObj[key] === undefined) {
this.eventObj[key] = {}; // 如果不存在key的事件列表 则初始化为空 可以理解为 一个公众号可以有多个人订阅
}
const callbackIndex = this.callbackId++; // 先赋值再添加 每添加一个订阅者 人数加1
this.eventObj[key][callbackIndex] = callback; //将回调函数添加到事件列表中 可以理解为添加订阅公众号人数,并为每个订阅者提供通知服务
return callbackIndex; // 返回订阅者id 可以理解为是第几个订阅的人
};
// 发布
EventBus.prototype.$emit = function(key, ...args) {
const EventList = this.eventObj[key]; // 获取本次发布内容对应的所有订阅者
Object.keys(EventList).forEach((fnKey) => {
EventList[fnKey](...args); // 执行传入的函数 可以理解为挨个通知所有订阅者本次发布的内容
if (fnKey.indexOf("once") > -1) {
// 只执行一次的订阅 执行完就删除
delete EventList[fnKey];
}
});
};
// 取消
EventBus.prototype.$off = function(key, id) {
delete this.eventObj[key][id]; // 删除订阅事件 可以理解为取消通知订阅者
if (this.eventObj[key].length === 0) {
// 如果没人关注公众号 就删除该事件
delete this.eventObj[key];
}
};
// 执行一次
EventBus.prototype.$once = function(key, callback) {
if (this.eventObj[key] === undefined) {
// 未订阅过该事件
this.eventObj[key] = {};
}
const callbackIndex = this.callbackId++; // 先赋值再添加 每添加一个订阅者 人数加1
this.eventObj[key]["once" + callbackIndex] = callback; //将回调函数添加到事件列表中 可以理解为添加订阅公众号人数,并为每个订阅者提供通知服务,使用once标记只订阅一条消息的订阅者
return callbackIndex; // 返回订阅者id 可以理解为是第几个订阅的人
};
接下来我们通过几个例子来验证这几个实现的功能。
1.发布、订阅
const eventBus = new EventBus();
eventBus.$on("gongzhonghao1", (content) => {
console.log(`用户1订阅了gongzhonghao1,${content}`);
});
eventBus.$on("gongzhonghao1", (content) => {
console.log(`用户2订阅了gongzhonghao1,${content}`);
});
eventBus.$emit("gongzhonghao1", "文章内容1");
eventBus.$emit("gongzhonghao1", "文章内容2");
取消订阅
const eventBus = new EventBus();
eventBus.$on("gongzhonghao1", (content) => {
console.log(`用户1订阅了gongzhonghao1,${content}`);
});
const id = eventBus.$on("gongzhonghao1", (content) => {
console.log(`用户2订阅了gongzhonghao1,${content}`);
});
eventBus.$emit("gongzhonghao1", "文章内容1");
eventBus.$off('gongzhonghao1', id)
eventBus.$emit("gongzhonghao1", "文章内容2");
在发布第二条消息之前取消了订阅公众号 所以用户2只收到了公众号1发布的第一条内容
3.订阅一次
const eventBus = new EventBus();
eventBus.$on("gongzhonghao1", (content) => {
console.log(`用户1订阅了gongzhonghao1,${content}`);
});
eventBus.$once("gongzhonghao1", (content) => {
console.log(`用户2订阅了gongzhonghao1,${content}`);
});
eventBus.$emit("gongzhonghao1", "文章内容1");
eventBus.$emit("gongzhonghao1", "文章内容2");
用户2只订阅了一次内容,所以无法收到第二条消息
# 面试官:请手写一个EventBus,让我看看你的代码能力!