如何实现一个自定义事件系统?
介绍如何创建和管理自定义事件系统,包括基于 DOM 和独立 EventTarget 的方法。
实现自定义事件系统有两种主流方式:基于 DOM 元素的事件模型和基于纯粹 EventTarget
对象的事件模型。下面是详细步骤:
1. 基于 DOM 元素的事件系统(兼容浏览器环境)
步骤:
// 1. 创建自定义事件实例
const myEvent = new CustomEvent('customEventName', {
detail: { key: '任意自定义数据' }, // 通过 detail 传递数据
bubbles: true, // 允许冒泡
cancelable: true // 允许阻止默认行为
});
// 2. 监听元素上的自定义事件
const element = document.getElementById('target');
element.addEventListener('customEventName', (event) => {
console.log('事件触发!携带数据:', event.detail.key);
});
// 3. 在目标元素上触发事件
element.dispatchEvent(myEvent);
关键点:
- 使用
new CustomEvent()
创建事件(废弃旧createEvent()
方法),支持传递复杂数据。 - 通过
addEventListener()
注册监听器,通过dispatchEvent()
派发事件。 - 支持冒泡/捕获阶段:事件可通过 DOM 树向上传播(类似原生事件)。
2. 基于独立 EventTarget 的事件系统(不依赖 DOM,适用于纯 JavaScript 逻辑)
步骤:
// 1. 创建独立的事件目标对象
const eventBus = new EventTarget();
// 2. 注册事件监听器
eventBus.addEventListener('logEvent', (event) => {
console.log(`日志内容:${event.detail.message}`);
});
// 3. 派发事件并携带数据
const logDataEvent = new CustomEvent('logEvent', {
detail: { message: '自定义日志内容' }
});
eventBus.dispatchEvent(logDataEvent);
关键点:
EventTarget
构造函数可直接创建非 DOM 绑定的事件管理器,适用于模块间通信。- 可多个独立事件总线并行使用(如日志事件总线 vs 状态更新事件总线)。
通用原则
- 数据传递:所有自定义数据应在
new CustomEvent()
的第 2 个参数的detail
字段中封装。 - 事件类型命名:建议使用驼峰命名(如
userStateChange
)避免冲突。 - 解除监听:通过
removeEventListener()
防止内存泄漏。
⚠️ 注意:旧 API 如
document.createEvent()
已废弃,不推荐在新项目中使用。