用 new CustomEvent 创建自定义事件时,必须通过 detail 选项传入业务数据,再调用 dispatchEvent 触发;监听方从 event.detail 安全读取,detail 是唯一推荐的数据载体,支持任意类型但需注意跨上下文限制。
用
创建携带业务数据的自定义事件,关键在于正确使用
选项传入任意结构的数据对象,再通过
触发,监听方从事件对象的
属性中读取。
detail 是唯一推荐的数据载体
构造函数支持一个可选的配置对象,其中
是唯一用于传递自定义业务数据的字段。它没有类型限制,可以是字符串、数字、数组、普通对象,甚至 Class 实例(需注意序列化限制)。
✅ 推荐写法:
❌ 避免在
外额外挂属性,比如
—— 这些不会被自动注入到事件实例上
⚠️ 注意:
中若含函数、DOM 节点或循环引用,在跨上下文(如 iframe、Web Worker)传递时可能丢失或报错
触发事件要绑定到有效目标节点
自定义事件需调用
方法才能真正发出,且必须作用于一个有效的 DOM 节点(如
、
或某个元素),不能直接对事件对象调用。
常见目标选择:
(全局广播)、
(组件内通信)
确保目标节点已存在于 DOM 中,否则会静默失败(不报错但监听器收不到)
如果需要冒泡,构造时设
;需要被
拦截,就设
监听时从 event.detail 安全取值
监听函数中,业务数据始终位于
,建议做存在性判断,避免因未传参导致
报错。
基础监听写法:
防御性写法:
配合 TypeScript 可定义接口增强类型提示,例如:
,然后
实际小例子:登录成功后通知全局
假设用户登录完成,前端需要通知多个模块更新状态:
new CustomEventdetaildispatchEventdetailCustomEventdetailnew CustomEvent('user-login', { detail: { id: 123, name: 'Alice', roles: ['admin'] } })detail{ detail: ..., userId: 456 }detaildispatchEventdocumentwindowdocument.dispatchEvent(evt)myButton.dispatchEvent(evt)bubbles: truestopPropagation()cancelable: trueevent.detailundefineddocument.addEventListener('user-login', e => console.log(e.detail.name))const data = e.detail ?? {}; console.log(data.id || 'unknown')interface LoginDetail { id: number; name: string; }e.detail as LoginDetail// 发送方(如登录表单提交后)
const loginSuccess = new CustomEvent('auth-success', {
detail: { token: 'abc123', user: { id: 789, avatar: '/u.png' } },
bubbles: true
});
document.dispatchEvent(loginSuccess);
// 监听方(如用户头像组件)
document.addEventListener('auth-success', e => {
const { token, user } = e.detail;
localStorage.setItem('auth-token', token);
renderAvatar(user.avatar);
});
