/** * 事件总线(轻量版),支持事件类型系统(泛型) * * 通过泛型参数可以为事件名与数据建立类型映射,从而在编译期获得类型检查与提示。 * * @example * interface Events { update: { id: string; idx: number }; message: string } * const evt = new RawEvents() * evt.on('update', (data) => console.log(data.id)) * evt.emit('update', { id: 'a', idx: 1 }) */ export class RawEvents { /** * 事件映射表,键为事件名,值为对应的监听器数组。 * @private */ events: { [type: string]: Function[] } = {} /** * 注册事件监听器。相同函数不会被重复添加。 * * @param key 事件名称 * @param listener 监听函数,签名为 (data?: TEventMap[EventKey], options?: any) => any */ on( key: EventKey | string, listener: (data: TEventMap[EventKey], options?: any) => any ) { let listenerList = this.events[key as string] if (listenerList) { if (listenerList.indexOf(listener) === -1) listenerList.push(listener) } else { listenerList = [] listenerList.push(listener) this.events[key as string] = listenerList } } /** * 注销事件监听器。 * * - 若提供 listener,则仅移除该函数。 * - 若未提供 listener,则清空该事件的所有监听器。 * * @param key 事件名称 * @param listener 可选,要移除的监听函数 */ off( key: EventKey | string, listener?: (data?: TEventMap[EventKey], options?: any) => any ) { let listenerList = this.events[key as string] if (listenerList) { if (listener) { let index = listenerList.indexOf(listener) if (index > -1) listenerList.splice(index, 1) } else { this.events[key as string] = [] } } } /** * 同步触发事件,按注册顺序调用所有监听器,不等待异步操作完成。 * * @param key 事件名称 * @param data 传递给监听器的数据 * @param options 额外选项(内部透传) */ emit(key: EventKey | string, data?: TEventMap[EventKey], options?: any) { let listenerList = this.events[key as string] if (listenerList) { for (let func of listenerList) { func(data, options) } } } /** * 异步触发事件,按注册顺序逐一 await 每个监听器(若监听器返回 Promise 则等待其完成)。 * 适用于需要依赖监听器执行顺序或等待其完成的场景。 * * @param key 事件名称 * @param data 传递给监听器的数据 * @param options 额外选项(内部透传) */ async emitAsync( key: EventKey | string, data?: TEventMap[EventKey], options?: any ) { let listenerList = this.events[key as string] if (listenerList) { for (let func of listenerList) { await func(data, options) } } } /** * 注册一次性监听器,触发后自动移除。 * * @param key 事件名称 * @param listener 监听函数,触发一次后会被移除 */ once( key: EventKey | string, listener?: (data?: TEventMap[EventKey], options?: any) => any ) { let func = (data: any, options?: any) => { listener && listener(data, options) this.off(key, func as any) } this.on(key, func as any) } /** * 清除所有事件与监听器。 */ clear() { this.events = {} } }