Skip to main content

CustomEvent

概述

CustomEvent 是 ECMAScript 标准提供的原生 API,用于创建和触发自定义事件。它允许开发者定义任意名称的事件类型(如 my-clickdata-loaded),并传递自定义数据,实现组件间通信或复杂交互逻辑。

语法与核心方法

1. 创建自定义事件

通过 new CustomEvent() 构造函数创建事件对象:

const event = new CustomEvent('eventName', {
detail: { /* 自定义数据 */ },
bubbles: true, // 是否冒泡
cancelable: true, // 是否可取消
composed: true // 是否穿透 Shadow DOM
});

2. 触发事件

在元素或 window 对象上调用 dispatchEvent()

element.dispatchEvent(event);

3. 监听事件

使用 addEventListener()on 属性绑定处理函数:

element.addEventListener('eventName', (e) => {
console.log(e.detail); // 获取自定义数据
});

关键属性详解

属性类型说明
detailObject自定义数据容器(必选),可通过 event.detail.key = value 修改。
bubblesboolean默认 false,设为 true 后事件会向父元素冒泡。
cancelableboolean默认 false,设为 true 后可通过 e.preventDefault() 阻止默认行为。
composedboolean默认 false,设为 true 后事件可穿透 Shadow DOM(仅限跨宿主传播)。

场景示例

示例 1:基础用法

<div id="btn">点击我</div>
<div id="log"></div>

<script>
// 定义按钮点击事件
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
// 创建并触发自定义事件,携带数据
const event = new CustomEvent('custom-btn-click', {
detail: {
timestamp: new Date().toISOString(),
message: '按钮被点击了!'
}
});
btn.dispatchEvent(event);
});

// 监听自定义事件
document.addEventListener('custom-btn-click', (e) => {
const log = document.getElementById('log');
log.innerHTML = `<p>时间:${e.detail.timestamp}<br>内容:${e.detail.message}</p>`;
});
</script>

效果:点击按钮后,在页面显示点击时间和消息。

示例 2:事件冒泡与阻止默认行为

<div id="parent">
<button id="child">子按钮</button>
</div>

<script>
// 子元素触发带冒泡的自定义事件
document.getElementById('child').addEventListener('click', () => {
const event = new CustomEvent('child-event', {
bubbles: true,
cancelable: true,
detail: { text: '来自子元素' }
});
// 触发事件前检查是否被取消
if (!event.defaultPrevented) {
this.dispatchEvent(event);
}
});

// 父元素监听并阻止冒泡
document.getElementById('parent').addEventListener('child-event', (e) => {
console.log('父元素收到事件:', e.detail.text);
e.preventDefault(); // 阻止进一步冒泡
});

// 全局监听(不会触发,因已被父元素阻止)
window.addEventListener('child-event', () => {
console.log('全局监听未触发');
});
</script>

输出

父元素收到事件: 来自子元素

示例 3:跨 Shadow DOM 通信

<template id="shadow-template">
<style>
.shadow-box { background: #eee; padding: 10px; }
</style>
<div class="shadow-box" id="shadow-content">
Shadow DOM 内容
</div>
</template>

<div id="host"></div>

<script>
// 创建 Shadow DOM
const host = document.getElementById('host');
const shadowRoot = host.attachShadow({ mode: 'open' });
const template = document.getElementById('shadow-template');
shadowRoot.appendChild(template.content.cloneNode(true));

// 在 Shadow DOM 内触发自定义事件(设置 composed: true)
const shadowContent = shadowRoot.getElementById('shadow-content');
shadowContent.addEventListener('click', () => {
const event = new CustomEvent('shadow-message', {
composed: true, // 允许穿透到宿主
detail: { text: '来自 Shadow DOM' }
});
shadowContent.dispatchEvent(event);
});

// 宿主元素监听穿透事件
host.addEventListener('shadow-message', (e) => {
console.log('宿主收到 Shadow DOM 消息:', e.detail.text);
});
</script>

效果:点击 Shadow DOM 内容时,宿主元素的监听器会收到消息。

注意事项

  1. 事件名称规范

    • 自定义事件名称应使用 小驼峰命名法(如 user-login),与内置事件(如 click)区分。
    • 避免使用浏览器保留名称(如 loaderror),除非明确重写行为。
  2. 兼容性处理

    • 旧版浏览器(如 IE)需使用 polyfill:

      javascript

      if (!window.CustomEvent) {
      window.CustomEvent = function (name, params) {
      params = params || { bubbles: false, cancelable: false };
      const event = document.createEvent('Event');
      event.initEvent(name, params.bubbles, params.cancelable);
      event.detail = params.detail;
      return event;
      };
      }
  3. 性能优化

    • 频繁触发事件可能导致性能问题,建议合理控制事件频率。
    • 使用事件委托(Event Delegation)减少监听器数量。

应用场景

  • 组件化开发:如 React/Vue 中通过自定义事件实现父子组件通信。
  • 第三方库扩展:为现有库(如 lodash)添加插件式事件系统。
  • 复杂交互逻辑:如表单多步骤验证、动画状态同步。

通过 CustomEvent,开发者可以构建更灵活、可维护的代码结构,实现与非侵入式的组件交互。