import { has } from '@/plugin/utils'; export interface EmitableEvent { [event: string]: (...params: any) => any; } interface Listener any> { fn: T; once?: boolean; immediate?: boolean; } interface ListenerOptions { once: boolean; immediate: boolean; } type EmitFn any> = ( events: Listener[], ...params: Parameters ) => any; export class EventEmitter { private events: { [P in keyof T]?: Listener[]; } = {}; private emitted: (keyof T)[] = []; private emitter: { [P in keyof T]?: EmitFn; } = {}; /** * 监听某个事件 * @param event 要监听的事件类型 * @param fn 触发事件时执行的函数 * @param options 监听选项 */ on( event: K, fn: T[K], options?: Partial ) { if (options?.immediate && this.emitted.includes(event)) { fn(); if (!options.once) { this.events[event] ??= []; this.events[event]?.push({ fn }); } return; } this.events[event] ??= []; this.events[event]?.push({ fn, once: options?.once }); } /** * 取消监听某个事件 * @param event 要取消监听的事件类型 * @param fn 要取消监听的函数 */ off(event: K, fn: T[K]) { const index = this.events[event]?.findIndex(v => v.fn === fn); if (index === -1 || index === void 0) return; this.events[event]?.splice(index, 1); } /** * 监听事件,并只触发一次 * @param event 要监听的事件 * @param fn 监听函数 */ once(event: K, fn: T[K]) { this.on(event, fn, { once: true }); } /** * 触发某个事件 * @param event 要触发的事件类型 * @param params 传入的参数 */ emit( event: K, ...params: Parameters ): ReturnType[]; emit(event: K, ...params: Parameters): R; emit(event: K, ...params: Parameters): any { if (!this.emitted.includes(event)) { this.emitted.push(event); } const events = (this.events[event] ??= []); if (!!this.emitter[event]) { const returns = this.emitter[event]!(events, ...params); this.events[event] = events.filter(v => !v.once); return returns; } else { const returns: ReturnType[] = []; for (let i = 0; i < events.length; i++) { const e = events[i]; returns.push(e.fn(...(params as any))); } this.events[event] = events.filter(v => !v.once); return returns; } } /** * 设置一个事件的执行器(emitter) * @param event 要设置的事件 * @param fn 事件执行器,留空以清除触发器 */ setEmitter(event: K, fn?: EmitFn) { this.emitter[event] = fn; } /** * 取消监听所有的事件,删除所有监听函数 */ removeAllListeners(): void; /** * 取消监听一个事件的所有函数 * @param event 要取消监听的事件 */ removeAllListeners(event: keyof T): void; removeAllListeners(event?: keyof T) { if (has(event)) this.events[event] = []; else this.events = {}; } } type IndexedSymbol = number | string | symbol; export class IndexedEventEmitter< T extends EmitableEvent > extends EventEmitter { private fnMap: { [P in keyof T]?: Map; } = {}; /** * 监听事件,并将函数与唯一标识符绑定 * @param event 事件类型 * @param symbol 监听函数的唯一标识符 * @param fn 监听函数 * @param options 监听配置 */ onIndex( event: K, symbol: IndexedSymbol, fn: T[K], options: Partial ) { const map = this.ensureMap(event); if (map.has(symbol)) { console.warn( `监听${String(event)}出错:已存在标识符为${String( symbol )}的监听函数,已将其覆盖` ); this.offIndex(event, symbol); } map.set(symbol, fn); this.on(event, fn, options); } /** * 监听事件,绑定唯一标识符,但监听函数只会执行一次 * @param event 要监听的事件 * @param symbol 监听函数的唯一标识符 * @param fn 监听函数 */ onceIndex(event: K, symbol: IndexedSymbol, fn: T[K]) { this.onIndex(event, symbol, fn, { once: true }); } /** * 取消监听一个事件 * @param event 要取消监听的事件 * @param symbol 取消监听的函数的唯一标识符 */ offIndex(event: K, symbol: IndexedSymbol) { const map = this.ensureMap(event); const fn = map.get(symbol); if (!fn) return; this.off(event, fn); } private ensureMap(event: K) { return this.fnMap[event] ?? new Map(); } }