You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求推荐可跨类全局触发事件的ES6单例EventEmitter(附示例)

推荐单例ES6 EventEmitter实现(跨类全局触发)

你要的这种无需继承、单例模式、支持跨类全局触发事件的EventEmitter,其实完全可以自己实现一个轻量版本,比找第三方工具更可控,而且完全符合你的需求。我给你写一个完整的实现和跨类使用示例:

第一步:实现单例EventEmitter

创建一个SingleTonEmitter.js文件,这里我们实现一个极简但够用的EventEmitter,并且确保它是单例:

// SingleTonEmitter.js
class EventEmitter {
  constructor() {
    // 存储事件和对应的回调函数集合
    this.events = new Map();
  }

  // 监听事件
  on(eventName, callback) {
    if (!this.events.has(eventName)) {
      this.events.set(eventName, []);
    }
    this.events.get(eventName).push(callback);
  }

  // 触发事件(对应你示例里的dispatch)
  emit(eventName, ...args) {
    if (this.events.has(eventName)) {
      this.events.get(eventName).forEach(callback => {
        callback(...args);
      });
    }
  }

  // 可选:移除单个事件监听
  off(eventName, callback) {
    if (this.events.has(eventName)) {
      const callbacks = this.events.get(eventName);
      const index = callbacks.indexOf(callback);
      if (index !== -1) {
        callbacks.splice(index, 1);
        // 如果该事件没有回调了,移除这个事件
        if (callbacks.length === 0) {
          this.events.delete(eventName);
        }
      }
    }
  }

  // 可选:监听一次事件,触发后自动移除
  once(eventName, callback) {
    const wrapper = (...args) => {
      callback(...args);
      this.off(eventName, wrapper);
    };
    this.on(eventName, wrapper);
  }
}

// 导出单例实例,确保所有导入的地方用的都是同一个对象
export default new EventEmitter();

第二步:跨类使用示例

现在你可以在任何类里导入这个单例Emitter,直接使用:

监听事件的类(Listener)

// Listener.js
import emitter from './SingleTonEmitter.js';

export class Listener {
  constructor() {
    // 监听'somethingHappened'事件
    emitter.on('somethingHappened', (data) => {
      this.onChange(data);
    });
    // 也可以用once监听一次性事件
    emitter.once('oneTimeEvent', () => {
      console.log('这个事件只会触发一次');
    });
  }

  onChange(data) {
    console.log('收到事件通知,数据是:', data);
    // 这里写你的业务逻辑
  }
}

触发事件的类(DispatchClass)

// DispatchClass.js
import emitter from './SingleTonEmitter.js';

export class DispatchClass {
  triggerEvent() {
    // 触发'somethingHappened'事件,并传递数据
    emitter.emit('somethingHappened', { message: 'Hello from DispatchClass' });
    // 触发一次性事件
    emitter.emit('oneTimeEvent');
  }
}

测试跨类触发

// 测试代码
import { Listener } from './Listener.js';
import { DispatchClass } from './DispatchClass.js';

// 实例化监听类
const listener = new Listener();
// 实例化触发类
const dispatcher = new DispatchClass();

// 调用触发方法,Listener会收到事件
dispatcher.triggerEvent();
// 再次调用,一次性事件不会再触发
dispatcher.triggerEvent();

为什么这个方案符合你的需求?

  • 单例模式:所有导入的地方用的都是同一个EventEmitter实例,天然支持全局事件传递
  • 无需继承:不需要让你的类继承EventEmitter,直接导入单例实例即可使用
  • 跨类触发:Listener和DispatchClass完全独立,只要导入同一个Emitter,就能实现事件通信
  • 轻量可控:你可以根据自己的需求扩展方法(比如上面的off、once),不需要引入多余的第三方依赖

如果需要更复杂的功能(比如事件命名空间、错误处理),也可以在这个基础上扩展,或者考虑使用mitt这个极小的第三方库(不过自己实现的已经完全够用大部分场景了)。

内容的提问来源于stack exchange,提问作者Patrick Teulings

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:58:33