前端面试中最常见的设计模式:发布/订阅模式(eventBus)
前言
在Vue.js中,每个组件都是独立的,它们之间的通信需要通过父子组件通信、props和$emit
等方式进行。但是,如果组件之间没有明显的层次关系或者需要在不同的层次
之间进行通信,那么EventBus模式就可以帮助我们实现这样的通信。可以将EventBus理解为一个事件总线
,所有组件都可以在其中注册监听事件,并发送事件,这样就可以方便地实现组件之间的通信。
Vue2.x
中使用EventBus模式具体步骤如下:
- 创建一个新的js文件,命名为
eventBus.js
,将Vue实例
作为默认导出,供其他组件使用。
import Vue from 'vue';
export default new Vue();
- 在需要使用eventBus的组件中,使用
import
导入eventBus.js
文件,并在组件中使用eventBus实例
。
import eventBus from './eventBus.js';
export default {
methods: {
sendData() {
const data = {
message: 'Hello world!'
};
// 发送事件并传递数据
eventBus.$emit('my-event', data);
}
}
}
- 在需要接收数据的组件中,使用
import
导入eventBus.js
文件,并在组件中使用eventBus实例。
import eventBus from './eventBus.js';
export default {
created() {
// 监听事件并接收数据
eventBus.$on('my-event', function(data) {
// 接收数据,并处理
console.log(data.message); // 输出:Hello world!
});
}
}
那到底什么是EventBus模式
,接下来让我们详细了解一下。
发布/订阅(eventBus)模式
EventBus模式
是一种在软件架构中广泛使用的模式,它是一种基于发布/订阅模式
的事件处理模式,用于处理组件间通信。在这种模式下,一个事件总线(EventBus)
充当一个中心化的通信器,负责组件之间的事件通信。
在一个应用程序中,不同的组件(如模块、类、对象等)
可能需要相互通信。而这些组件之间的通信可能会导致代码变得复杂和难以维护。使用EventBus模式,组件只需要订阅
它们关心的事件,当事件发生时,总线将通知
订阅该事件的组件,从而实现组件之间的通信。
EventBus模式的优点:
简化组件间通信
:EventBus模式可以将组件间的通信简化为发布/订阅模式,从而减少了组件之间的耦合度,降低了代码的复杂性和维护成本。跨越多个层级
:EventBus模式可以跨越多个层级进行通信,从而可以在复杂的组件层次结构中轻松地进行通信。可以扩展
:通过使用EventBus模式,我们可以轻松地向应用程序中添加新的组件或功能,而不需要修改现有的组件或功能。这样可以提高应用程序的灵活性和可扩展性。易于调试
:由于EventBus模式将组件之间的通信转换为事件的发布和订阅,因此可以轻松地调试应用程序中的事件处理器,从而更好地了解应用程序的行为。
总之,EventBus模式是一种非常有用的设计模式,可以帮助我们实现组件之间的通信、跨层级的通信以及解耦组件等目标。如果你在开发中遇到了这些问题,那么EventBus模式就是一个很好的选择。
JavaScript实现发布/订阅(eventBus)模式
在了解完什么是发布/订阅(eventBus)模式后,我们就简单地用JavaScript
手撸一下代码实现
class EventBus {
// 创建EventBus类
constructor() {
// 构造函数,用于初始化listeners对象
this.listeners = {};
// 用于存储事件和对应的监听器
}
on(event, listener) {
// 用于订阅事件,将事件和对应的监听器存储在listeners对象中
if (!this.listeners[event]) {
// 如果listeners对象中没有对应的事件,则创建一个新的数组
this.listeners[event] = [];
}
this.listeners[event].push(listener);
// 将监听器添加到事件的监听器列表中
}
off(event, listener) {
// 用于取消订阅事件,将事件和对应的监听器从listeners对象中移除
if (this.listeners[event]) {
// 如果listeners对象中存在对应的事件
const index = this.listeners[event].indexOf(listener);
// 找到对应监听器在事件监听器列表中的索引
if (index > -1) {
// 如果索引存在
this.listeners[event].splice(index, 1);
// 将监听器从事件监听器列表中移除
}
}
}
emit(event, ...args) {
// 用于触发事件,将事件和相关参数传递给对应的监听器
if (this.listeners[event]) {
// 如果listeners对象中存在对应的事件
this.listeners[event].forEach(listener => listener(...args));
// 遍历事件的监听器列表,依次执行监听器并传递参数
}
}
}
以下是一个具体的应用代码示例,它使用EventBus模式实现了一个简单的登录和登出
功能:
// 创建EventBus实例
const bus = new EventBus();
// 订阅login事件,当事件触发时执行相关操作
bus.on('login', function(username) {
console.log(`欢迎登录,${username}!`);
});
// 订阅logout事件,当事件触发时执行相关操作
bus.on('logout', function(username) {
console.log(`再见,${username}!`);
});
// 模拟登录操作
function login(username) {
// 触发login事件,并传递用户名参数
bus.emit('login', username);
}
// 模拟登出操作
function logout(username) {
// 触发logout事件,并传递用户名参数
bus.emit('logout', username);
}
// 执行登录操作
login('张三');
// 执行登出操作
logout('张三');
这段代码中,我们首先创建了一个EventBus实例
,然后订阅了(on)
login和logout事件,并在事件触发时执行相关操作。接着,我们模拟了登录和登出操作,分别触发(emit)
了login和logout事件,并传递了用户名参数。最后,我们执行了这两个操作,查看控制台输出结果。
文章最后
当我们在开发中遇到组件间通信的问题时,EventBus模式可以帮助我们解决这些问题,它将组件间的通信简化为事件的发布和订阅,从而降低了组件之间的耦合度,提高了代码的灵活性和可扩展性。
虽然EventBus模式在一些场景下可能不如其他解决方案,但是它仍然是一种非常有用的设计模式,可以帮助我们实现复杂应用程序中组件之间的通信、跨层级的通信以及解耦组件等目标。最重要的是,前端面试真的经常问啊
。
在实际应用中,我们可以根据实际情况选择使用EventBus模式或其他解决方案,以满足我们的需求。总之,了解和掌握EventBus模式对于提高我们的开发能力和代码质量(应付面试)
是非常有帮助的。
转载自:https://juejin.cn/post/7205841266906923069