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

如何实现可全局调用的JavaScript自定义事件分发器

全局跨模块事件分发器实现方案

第一步:修复原有Dispatcher类的问题并实现单例导出

原有代码首先存在基础bug:constructor中未初始化events属性,直接调用方法会抛出undefined错误。我们利用ES模块的单例特性,导出初始化后的实例即可实现全局共享,无需挂载到window对象。

// dispatcher.js
class Dispatcher{
    constructor(){
        // 初始化事件存储对象,用Object.create(null)避免原型链污染
        this.events = Object.create(null)
    }

    addListener (event, callback) {
        if (typeof callback !== 'function') {
            console.error(`The listener callback must be a function, the given type is ${typeof callback}`);
            return false;
        }
        if (typeof event !== 'string') {
            console.error(`The event name must be a string, the given type is ${typeof event}`);
            return false;
        }
            
        if (this.events[event] === undefined) {
            this.events[event] = {
                listeners: []
            }
        }
            
        this.events[event].listeners.push(callback);
    }

    removeListener(event, callback){
        if(this.events[event] === undefined){
            console.error(`This event: ${event} does not exist`);
            return false;
        }
        // 优化:直接比较函数引用,避免内容相同的不同函数被误删除
        this.events[event].listeners = this.events[event].listeners.filter(listener => listener !== callback)
    }

    dispatch(event, details){
        if(this.events[event] === undefined){
            console.error(`This event: ${event} does not exist`);
            return false;
        }
        // 浅拷贝一份数组执行,避免回调里删除监听导致遍历异常
        [...this.events[event].listeners].forEach((listener) => {
            listener(details);
        })
    }
}

// 导出单例实例,所有模块导入的都是同一个实例,天然实现全局共享
export default new Dispatcher()
// 如需创建独立的分发器实例,可额外导出类
export { Dispatcher }

第二步:跨模块使用示例

1. 在被导入的模块(如API2.js)中派发事件

// /js/API2.js
import dispatcher from './dispatcher.js'

export class API2 {
    fetchData() {
        // 业务逻辑执行完成后派发事件
        dispatcher.dispatch('api-data-loaded', {
            data: {id: 1, content: 'test'}
        })
    }
}

2. 在main.js中监听事件

// main.js
import dispatcher from './dispatcher.js'
import { API2 } from '/js/API2.js'

// 注册监听
dispatcher.addListener('api-data-loaded', (details) => {
    console.log('接收到API2派发的事件', details)
})

// 触发API2逻辑,可正常收到事件通知
const api = new API2()
api.fetchData()

原挂载window方案失效的常见原因

  • 挂载的是Dispatcher类而非初始化后的实例,直接调用类的静态方法自然不存在
  • 模块加载顺序错误,其他模块导入使用dispatcher时,还未执行挂载window的逻辑
  • ES模块默认是隔离作用域,若你在模块内声明的dispatcher未显式挂到window上,其他模块无法访问

内容的提问来源于stack exchange,提问作者Nik Hendricks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 02:54:07