自定义 event emitter

98 阅读1分钟

想要一个事件订阅和发射器,不想引用三方库,直接自己定义一个, 代码其实不多,这样可以减少依赖,支持 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++
});