想要一个事件订阅和发射器,不想引用三方库,直接自己定义一个, 代码其实不多,这样可以减少依赖,支持 once 和 clear ,主要是 emit 发射事件,on 订阅事件。
定义
type EventCallback<T = any> = (payload: T) => void;
type EventMap = Record<string, EventCallback>;
export class Emitter<Events extends EventMap> {
private events: Map<keyof Events, EventCallback[]> = new Map();
on<EventName extends keyof Events>(
event: EventName,
callback: Events[EventName]
) {
const handlers = this.events.get(event) || [];
handlers.push(callback);
this.events.set(event, handlers);
}
off<EventName extends keyof Events>(
event: EventName,
callback: Events[EventName]
) {
const handlers = this.events.get(event);
if (handlers) {
handlers.splice(handlers.indexOf(callback) >>> 0, 1);
}
}
emit<EventName extends keyof Events>(
event: EventName,
...payload: Parameters<Events[EventName]>
) {
const handlers = this.events.get(event);
if (handlers) {
handlers.forEach((handler) => handler.apply(null, payload));
}
}
once<EventName extends keyof Events>(
event: EventName,
callback: Events[EventName]
) {
const onceHandler: Events[EventName] = ((...args) => {
this.off(event, onceHandler);
callback.apply(null, args);
}) as Events[EventName];
this.on(event, onceHandler);
}
clear() {
this.events.clear();
}
}
使用
// 创建全局实例(可选)
export const emitter = new Emitter<{
// 在此定义全局事件类型示例:
'toast:show': (payload: { message: string; type?: 'success' | 'error' }) => void,
'modal:open': (payload: string) => void,
// 添加更多事件类型...
}>();
// Composition API 封装(可选)
export function useEmitter() {
// 可根据需要返回全局实例或新实例
return emitter;
}
const emitter = useEmitter();
// 发布事件
const onTest = () => {
emitter.emit('modal:open', 'test');
};
// 订阅事件
emitter.on('modal:open', (msg: string) => {
console.log(msg);
count.value++
});