likes
comments
collection
share

前端面试中最常见的设计模式:发布/订阅模式(eventBus)

作者站长头像
站长
· 阅读数 15

前言

在Vue.js中,每个组件都是独立的,它们之间的通信需要通过父子组件通信、props和$emit等方式进行。但是,如果组件之间没有明显的层次关系或者需要在不同的层次之间进行通信,那么EventBus模式就可以帮助我们实现这样的通信。可以将EventBus理解为一个事件总线,所有组件都可以在其中注册监听事件,并发送事件,这样就可以方便地实现组件之间的通信。 Vue2.x中使用EventBus模式具体步骤如下:

  1. 创建一个新的js文件,命名为eventBus.js,将Vue实例作为默认导出,供其他组件使用。
import Vue from 'vue';
export default new Vue();
  1. 在需要使用eventBus的组件中,使用import导入eventBus.js文件,并在组件中使用eventBus实例
import eventBus from './eventBus.js';

export default {
  methods: {
    sendData() {
      const data = {
        message: 'Hello world!'
      };
      // 发送事件并传递数据
      eventBus.$emit('my-event', data);
    }
  }
}
  1. 在需要接收数据的组件中,使用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模式的优点:

  1. 简化组件间通信:EventBus模式可以将组件间的通信简化为发布/订阅模式,从而减少了组件之间的耦合度,降低了代码的复杂性和维护成本。
  2. 跨越多个层级:EventBus模式可以跨越多个层级进行通信,从而可以在复杂的组件层次结构中轻松地进行通信。
  3. 可以扩展:通过使用EventBus模式,我们可以轻松地向应用程序中添加新的组件或功能,而不需要修改现有的组件或功能。这样可以提高应用程序的灵活性和可扩展性。
  4. 易于调试:由于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模式对于提高我们的开发能力和代码质量(应付面试)是非常有帮助的。