diff --git a/assets/core/common/event/EventDispatcher.ts b/assets/core/common/event/EventDispatcher.ts index 251439c..4435868 100644 --- a/assets/core/common/event/EventDispatcher.ts +++ b/assets/core/common/event/EventDispatcher.ts @@ -1,185 +1,182 @@ -import type { ListenerFunc, ListenerFuncTyped } from './EventMessage'; -import type { TypedEventMap } from './MessageManager'; -import { EventData } from './EventData'; -import { EventDataPool } from './EventDataPool'; -import { message } from './MessageManager'; - -/** 批量注册、移除全局事件对象(用于组件级事件管理) */ -export class EventDispatcher { - /** 本地事件列表,用于批量清理 */ - private events: Map> = new Map(); - - /** - * 注册全局事件(强类型) - * @param event 事件名(枚举) - * @param listener 处理事件的侦听器函数 - * @param object 侦听函数绑定的作用域对象 - */ - on(event: K, listener: ListenerFuncTyped, object: object): void; - - /** - * 注册全局事件(兼容旧用法) - * @param event 事件名 - * @param listener 处理事件的侦听器函数 - * @param object 侦听函数绑定的作用域对象 - */ - on(event: string, listener: ListenerFunc, object: object): void; - - /** - * 注册全局事件(实现) - */ - on(event: string, listener: ListenerFunc, object: object): void { - // 先注册到全局消息管理器 - message.on(event, listener, object); - - // 记录到本地事件列表,用于批量清理 - let eds = this.events.get(event); - if (eds == null) { - eds = []; - this.events.set(event, eds); - } - - const ed: EventData = EventDataPool.get(); - ed.event = event; - ed.listener = listener; - ed.object = object; - eds.push(ed); - } - - /** - * 监听一次事件,事件响应后,该监听自动移除(强类型) - * @param event 事件名(枚举) - * @param listener 事件触发回调方法 - * @param object 侦听函数绑定的作用域对象 - */ - once(event: K, listener: ListenerFuncTyped, object: object): void; - - /** - * 监听一次事件,事件响应后,该监听自动移除(兼容旧用法) - * @param event 事件名 - * @param listener 事件触发回调方法 - * @param object 侦听函数绑定的作用域对象 - */ - once(event: string, listener: ListenerFunc, object: object): void; - - /** - * 监听一次事件,事件响应后,该监听自动移除(实现) - */ - once(event: string, listener: ListenerFunc, object: object): void { - message.once(event, listener, object); - - // 记录到本地事件列表 - let eds = this.events.get(event); - if (eds == null) { - eds = []; - this.events.set(event, eds); - } - - const ed: EventData = EventDataPool.get(); - ed.event = event; - ed.listener = listener; - ed.object = object; - eds.push(ed); - } - - /** - * 移除全局事件(强类型) - * @param event 事件名(枚举) - * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) - * @param object 侦听函数绑定的作用域对象(可选) - */ - off(event: K, listener?: ListenerFuncTyped, object?: object): void; - - /** - * 移除全局事件(兼容旧用法) - * @param event 事件名 - * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) - * @param object 侦听函数绑定的作用域对象(可选) - */ - off(event: string, listener?: ListenerFunc, object?: object): void; - - /** - * 移除全局事件(实现) - */ - off(event: string, listener?: ListenerFunc, object?: object): void { - const eds = this.events.get(event); - if (!eds) return; - - // 如果没有指定 listener,移除该事件的所有监听器 - if (!listener) { - for (const eb of eds) { - message.off(event, eb.listener, eb.object); - EventDataPool.put(eb); - } - this.events.delete(event); - return; - } - - // 移除指定的监听器 - const length = eds.length; - for (let i = 0; i < length; i++) { - const eb = eds[i]; - if (eb.listener == listener && eb.object == object) { - message.off(event, eb.listener, eb.object); - EventDataPool.put(eb); - eds.splice(i, 1); - break; - } - } - - // 如果该事件已无监听器,删除事件 - if (eds.length == 0) { - this.events.delete(event); - } - } - - /** - * 触发全局事件(兼容旧用法) - * @param event 事件名 - * @param args 事件参数 - */ - - dispatchEvent(event: string, ...args: any[]): void { - message.dispatchEvent(event, ...args); - } - - /** - * 触发全局事件,支持同步与异步处理(兼容旧用法) - * @param event 事件名 - * @param args 事件参数 - */ - - dispatchEventAsync(event: string, ...args: any[]): Promise { - return message.dispatchEventAsync(event, ...args); - } - - /** - * 触发强类型事件(严格类型检查) - * @param event 事件名(枚举) - * @param data 事件数据(必须完全匹配类型定义) - */ - emit(event: K, data: TypedEventMap[K]): void { - message.emit(event, data); - } - - /** - * 触发强类型异步事件(严格类型检查) - * @param event 事件名(枚举) - * @param data 事件数据(必须完全匹配类型定义) - */ - emitAsync(event: K, data: TypedEventMap[K]): Promise { - return message.emitAsync(event, data); - } - - /** 清除所有的全局事件监听 */ - clear(): void { - // 直接遍历 Map,避免创建临时数组 - for (const [event, eds] of this.events) { - for (const eb of eds) { - message.off(event, eb.listener, eb.object); - EventDataPool.put(eb); - } - } - this.events.clear(); - } -} +import type { ListenerFunc, ListenerFuncTyped } from './EventMessage'; +import type { TypedEventMap } from './MessageManager'; +import { EventData } from './EventData'; +import { EventDataPool } from './EventDataPool'; +import { message } from './MessageManager'; + +/** 批量注册、移除全局事件对象(用于组件级事件管理) */ +export class EventDispatcher { + /** 本地事件列表,用于批量清理 */ + private events: Map> = new Map(); + + //#region 强类型事件方法 + + /** + * 注册全局事件(强类型) + * @param event 事件名(枚举) + * @param listener 处理事件的侦听器函数 + * @param object 侦听函数绑定的作用域对象 + */ + watch(event: K, listener: ListenerFuncTyped, object: object): void { + this.on(event as string, listener as ListenerFunc, object); + } + + /** + * 监听一次事件,事件响应后,该监听自动移除(强类型) + * @param event 事件名(枚举) + * @param listener 事件触发回调方法 + * @param object 侦听函数绑定的作用域对象 + */ + watchOnce(event: K, listener: ListenerFuncTyped, object: object): void { + this.once(event as string, listener as ListenerFunc, object); + } + + /** + * 移除全局事件(强类型) + * @param event 事件名(枚举) + * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) + * @param object 侦听函数绑定的作用域对象(可选) + */ + unwatch(event: K, listener?: ListenerFuncTyped, object?: object): void { + this.off(event as string, listener as ListenerFunc, object); + } + + /** + * 触发强类型事件(严格类型检查) + * @param event 事件名(枚举) + * @param data 事件数据(必须完全匹配类型定义) + */ + emit(event: K, data: TypedEventMap[K]): void { + message.emit(event, data); + } + + /** + * 触发强类型异步事件(严格类型检查) + * @param event 事件名(枚举) + * @param data 事件数据(必须完全匹配类型定义) + */ + emitAsync(event: K, data: TypedEventMap[K]): Promise { + return message.emitAsync(event, data); + } + + //#endregion + + //#region 弱类型事件方法 + + /** + * 注册全局事件 + * @param event 事件名 + * @param listener 处理事件的侦听器函数 + * @param object 侦听函数绑定的作用域对象 + */ + on(event: string, listener: ListenerFunc, object: object): void { + // 先注册到全局消息管理器 + message.on(event, listener, object); + + // 记录到本地事件列表,用于批量清理 + let eds = this.events.get(event); + if (eds == null) { + eds = []; + this.events.set(event, eds); + } + + const ed: EventData = EventDataPool.get(); + ed.event = event; + ed.listener = listener; + ed.object = object; + eds.push(ed); + } + + /** + * 监听一次事件,事件响应后,该监听自动移除 + * @param event 事件名 + * @param listener 事件触发回调方法 + * @param object 侦听函数绑定的作用域对象 + */ + once(event: string, listener: ListenerFunc, object: object): void { + message.once(event, listener, object); + + // 记录到本地事件列表 + let eds = this.events.get(event); + if (eds == null) { + eds = []; + this.events.set(event, eds); + } + + const ed: EventData = EventDataPool.get(); + ed.event = event; + ed.listener = listener; + ed.object = object; + eds.push(ed); + } + + /** + * 移除全局事件 + * @param event 事件名 + * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) + * @param object 侦听函数绑定的作用域对象(可选) + */ + off(event: string, listener?: ListenerFunc, object?: object): void { + const eds = this.events.get(event); + if (!eds) return; + + // 如果没有指定 listener,移除该事件的所有监听器 + if (!listener) { + for (const eb of eds) { + message.off(event, eb.listener, eb.object); + EventDataPool.put(eb); + } + this.events.delete(event); + return; + } + + // 移除指定的监听器 + const length = eds.length; + for (let i = 0; i < length; i++) { + const eb = eds[i]; + if (eb.listener == listener && eb.object == object) { + message.off(event, eb.listener, eb.object); + EventDataPool.put(eb); + eds.splice(i, 1); + break; + } + } + + // 如果该事件已无监听器,删除事件 + if (eds.length == 0) { + this.events.delete(event); + } + } + + /** + * 触发全局事件 + * @param event 事件名 + * @param args 事件参数 + */ + dispatchEvent(event: string, ...args: any[]): void { + message.dispatchEvent(event, ...args); + } + + /** + * 触发全局事件,支持同步与异步处理 + * @param event 事件名 + * @param args 事件参数 + */ + dispatchEventAsync(event: string, ...args: any[]): Promise { + return message.dispatchEventAsync(event, ...args); + } + + //#endregion + + /** 清除所有的全局事件监听 */ + clear(): void { + // 直接遍历 Map,避免创建临时数组 + for (const [event, eds] of this.events) { + for (const eb of eds) { + message.off(event, eb.listener, eb.object); + EventDataPool.put(eb); + } + } + this.events.clear(); + } +} diff --git a/assets/core/common/event/MessageManager.ts b/assets/core/common/event/MessageManager.ts index 285c971..14f5479 100644 --- a/assets/core/common/event/MessageManager.ts +++ b/assets/core/common/event/MessageManager.ts @@ -20,6 +20,9 @@ export interface TypedEventMap { // 业务层通过 declare module 扩展此接口 } +/** 获取 TypedEventMap 中所有事件 key 的联合类型 */ +export type EventMapKeys = keyof TypedEventMap; + /** * 全局消息管理 * @@ -42,53 +45,16 @@ export interface TypedEventMap { export class MessageManager { private events: Map> = new Map(); + //#region 强类型事件方法(提供给 Agent 自动生成用) + /** * 注册全局事件(强类型) * @param event 事件名(枚举) * @param listener 处理事件的侦听器函数 * @param object 侦听函数绑定的作用域对象 */ - on(event: K, listener: ListenerFuncTyped, object: object): void; - - /** - * 注册全局事件(兼容旧用法) - * @param event 事件名 - * @param listener 处理事件的侦听器函数 - * @param object 侦听函数绑定的作用域对象 - */ - on(event: string, listener: ListenerFunc, object: object): void; - - /** - * 注册全局事件(实现) - */ - on(event: string, listener: ListenerFunc, object: object): void { - if (!event || !listener) { - warn(`注册【${event}】事件的侦听器函数为空`); - return; - } - - let eds = this.events.get(event); - if (eds == null) { - eds = []; - this.events.set(event, eds); - } - - // 检查重复注册,如果已存在则直接返回,避免重复添加 - const length = eds.length; - for (let i = 0; i < length; i++) { - const bin = eds[i]; - if (bin.listener == listener && bin.object == object) { - warn(`名为【${event}】的事件重复注册侦听器`); - return; - } - } - - // 从对象池获取 EventData 对象 - const data: EventData = EventDataPool.get(); - data.event = event; - data.listener = listener; - data.object = object; - eds.push(data); + watch(event: K, listener: ListenerFuncTyped, object: object): void { + this.on(event as string, listener as ListenerFunc, object); } /** @@ -97,25 +63,8 @@ export class MessageManager { * @param listener 事件触发回调方法 * @param object 侦听函数绑定的作用域对象 */ - once(event: K, listener: ListenerFuncTyped, object: object): void; - - /** - * 监听一次事件,事件响应后,该监听自动移除(兼容旧用法) - * @param event 事件名 - * @param listener 事件触发回调方法 - * @param object 侦听函数绑定的作用域对象 - */ - once(event: string, listener: ListenerFunc, object: object): void; - - /** - * 监听一次事件,事件响应后,该监听自动移除(实现) - */ - once(event: string, listener: ListenerFunc, object: object): void { - const _listener: any = ($event: string, ...$args: any[]) => { - this.off(event, _listener, object); - listener.call(object, $event, ...$args); - }; - this.on(event, _listener, object); + watchOnce(event: K, listener: ListenerFuncTyped, object: object): void { + this.once(event as string, listener as ListenerFunc, object); } /** @@ -124,96 +73,8 @@ export class MessageManager { * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) * @param object 侦听函数绑定的作用域对象(可选) */ - off(event: K, listener?: ListenerFuncTyped, object?: object): void; - - /** - * 移除全局事件(兼容旧用法) - * @param event 事件名 - * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) - * @param object 侦听函数绑定的作用域对象(可选) - */ - off(event: string, listener?: Function, object?: object): void; - - /** - * 移除全局事件(实现) - */ - off(event: string, listener?: Function, object?: object): void { - const eds = this.events.get(event); - - if (!eds) { - log(`名为【${event}】的事件不存在`); - return; - } - - // 如果没有指定 listener,移除该事件的所有监听器 - if (!listener) { - for (const bin of eds) { - EventDataPool.put(bin); - } - this.events.delete(event); - return; - } - - // 移除指定的监听器 - const length = eds.length; - for (let i = 0; i < length; i++) { - const bin: EventData = eds[i]; - if (bin.listener == listener && bin.object == object) { - EventDataPool.put(bin); - eds.splice(i, 1); - break; - } - } - - if (eds.length == 0) { - this.events.delete(event); - } - } - - /** - * 触发全局事件(兼容旧用法) - * @param event 事件名 - * @param args 事件参数 - * @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历 - */ - - dispatchEvent(event: string, ...args: any[]): void { - const list = this.events.get(event); - if (list != null) { - const eds: Array = list.concat(); - const length = eds.length; - for (let i = 0; i < length; i++) { - const ed = eds[i]; - ed.listener.call(ed.object, event, ...args); - } - } - } - - /** - * 触发全局事件,支持同步与异步处理(兼容旧用法) - * @param event 事件名 - * @param args 事件参数 - * @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历 - */ - - dispatchEventAsync(event: string, ...args: any[]): Promise { - return new Promise((resolve) => { - const list = this.events.get(event); - if (list != null) { - const eds: Array = list.concat(); - const length = eds.length; - (async () => { - for (let i = 0; i < length; i++) { - const ed = eds[i]; - await Promise.resolve(ed.listener.call(ed.object, event, ...args)); - } - resolve(); - })(); - } - else { - resolve(); - } - }); + unwatch(event: K, listener?: ListenerFuncTyped, object?: object): void { + this.off(event as string, listener as ListenerFunc, object); } /** @@ -259,6 +120,145 @@ export class MessageManager { } }); } + + //#endregion + + //#region 弱类型事件方法 + + /** + * 注册全局事件 + * @param event 事件名 + * @param listener 处理事件的侦听器函数 + * @param object 侦听函数绑定的作用域对象 + */ + on(event: string, listener: ListenerFunc, object: object): void { + if (!event || !listener) { + warn(`注册【${event}】事件的侦听器函数为空`); + return; + } + + let eds = this.events.get(event); + if (eds == null) { + eds = []; + this.events.set(event, eds); + } + + // 检查重复注册,如果已存在则直接返回,避免重复添加 + const length = eds.length; + for (let i = 0; i < length; i++) { + const bin = eds[i]; + if (bin.listener == listener && bin.object == object) { + warn(`名为【${event}】的事件重复注册侦听器`); + return; + } + } + + // 从对象池获取 EventData 对象 + const data: EventData = EventDataPool.get(); + data.event = event; + data.listener = listener; + data.object = object; + eds.push(data); + } + + /** + * 监听一次事件,事件响应后,该监听自动移除 + * @param event 事件名 + * @param listener 事件触发回调方法 + * @param object 侦听函数绑定的作用域对象 + */ + once(event: string, listener: ListenerFunc, object: object): void { + const _listener: any = ($event: string, ...$args: any[]) => { + this.off(event, _listener, object); + listener.call(object, $event, ...$args); + }; + this.on(event, _listener, object); + } + + /** + * 移除全局事件 + * @param event 事件名 + * @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器) + * @param object 侦听函数绑定的作用域对象(可选) + */ + off(event: string, listener?: Function, object?: object): void { + const eds = this.events.get(event); + + if (!eds) { + log(`名为【${event}】的事件不存在`); + return; + } + + // 如果没有指定 listener,移除该事件的所有监听器 + if (!listener) { + for (const bin of eds) { + EventDataPool.put(bin); + } + this.events.delete(event); + return; + } + + // 移除指定的监听器 + const length = eds.length; + for (let i = 0; i < length; i++) { + const bin: EventData = eds[i]; + if (bin.listener == listener && bin.object == object) { + EventDataPool.put(bin); + eds.splice(i, 1); + break; + } + } + + if (eds.length == 0) { + this.events.delete(event); + } + } + + /** + * 触发全局事件 + * @param event 事件名 + * @param args 事件参数 + * @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历 + */ + dispatchEvent(event: string, ...args: any[]): void { + const list = this.events.get(event); + if (list != null) { + const eds: Array = list.concat(); + const length = eds.length; + for (let i = 0; i < length; i++) { + const ed = eds[i]; + ed.listener.call(ed.object, event, ...args); + } + } + } + + /** + * 触发全局事件,支持同步与异步处理 + * @param event 事件名 + * @param args 事件参数 + * @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历 + */ + dispatchEventAsync(event: string, ...args: any[]): Promise { + return new Promise((resolve) => { + const list = this.events.get(event); + if (list != null) { + const eds: Array = list.concat(); + const length = eds.length; + (async () => { + for (let i = 0; i < length; i++) { + const ed = eds[i]; + await Promise.resolve(ed.listener.call(ed.object, event, ...args)); + } + resolve(); + })(); + } + else { + resolve(); + } + }); + } + + //#endregion } export const message = new MessageManager();