如何实现一个自定义事件系统?

介绍如何创建和管理自定义事件系统,包括基于 DOM 和独立 EventTarget 的方法。

DOM操作 中等 事件处理 Event JavaScript

实现自定义事件系统有两种主流方式:基于 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() 已废弃,不推荐在新项目中使用。