自定义事件
JavaScript 中创建和使用自定义事件的方法
问题
如何在 JavaScript 中创建和使用自定义事件?
解答
方式一:使用 CustomEvent
浏览器原生提供的自定义事件 API。
// 创建自定义事件
const event = new CustomEvent('myEvent', {
detail: { message: 'Hello', id: 1 }, // 传递的数据
bubbles: true, // 是否冒泡
cancelable: true // 是否可取消
});
// 监听事件
document.addEventListener('myEvent', (e) => {
console.log(e.detail); // { message: 'Hello', id: 1 }
});
// 触发事件
document.dispatchEvent(event);
方式二:手写事件系统(发布订阅模式)
class EventEmitter {
constructor() {
this.events = {};
}
// 订阅事件
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
return this; // 支持链式调用
}
// 触发事件
emit(eventName, ...args) {
const callbacks = this.events[eventName];
if (callbacks) {
callbacks.forEach(cb => cb(...args));
}
return this;
}
// 取消订阅
off(eventName, callback) {
const callbacks = this.events[eventName];
if (callbacks) {
this.events[eventName] = callbacks.filter(cb => cb !== callback);
}
return this;
}
// 只订阅一次
once(eventName, callback) {
const wrapper = (...args) => {
callback(...args);
this.off(eventName, wrapper);
};
this.on(eventName, wrapper);
return this;
}
}
// 使用示例
const emitter = new EventEmitter();
// 订阅
emitter.on('login', (user) => {
console.log(`${user.name} 登录了`);
});
// 只触发一次
emitter.once('init', () => {
console.log('初始化完成');
});
// 触发
emitter.emit('login', { name: '张三' }); // 张三 登录了
emitter.emit('init'); // 初始化完成
emitter.emit('init'); // 不会输出
方式三:继承 EventTarget
class MyComponent extends EventTarget {
doSomething() {
// 触发自定义事件
this.dispatchEvent(new CustomEvent('done', {
detail: { result: 'success' }
}));
}
}
const component = new MyComponent();
component.addEventListener('done', (e) => {
console.log(e.detail.result); // success
});
component.doSomething();
关键点
CustomEvent是浏览器原生 API,通过detail传递数据- 手写事件系统本质是发布订阅模式,用对象存储事件名和回调数组
once实现:包装回调,执行后立即offEventTarget可被继承,让自定义类拥有事件能力- 注意
off时要移除正确的引用,匿名函数无法移除
目录