mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-06-03 18:49:23 +08:00
全局事件支持强类型事件参数
This commit is contained in:
@@ -1,94 +1,203 @@
|
||||
/*
|
||||
* @Author: dgflash
|
||||
* @Date: 2022-09-01 18:00:28
|
||||
* @LastEditors: dgflash
|
||||
* @LastEditTime: 2022-09-02 10:57:01
|
||||
*/
|
||||
import type { ListenerFunc } from './EventMessage';
|
||||
import { MessageEventData } from './MessageEventData';
|
||||
import type { TypedEventMap } from './MessageManager';
|
||||
import { EventData } from './EventData';
|
||||
import { EventDataPool } from './EventDataPool';
|
||||
import { message } from './MessageManager';
|
||||
|
||||
/**
|
||||
* 事件对象基类,继承该类将拥有发送和接收事件的能力
|
||||
*
|
||||
* @性能优化
|
||||
* - 懒加载 MessageEventData 实例,未使用事件功能时不占用内存
|
||||
* - 支持批量清理事件,避免逐个移除的性能损耗
|
||||
* - 使用对象池管理内部 EventData 对象
|
||||
*
|
||||
* @内存管理
|
||||
* ⚠️ 必须在对象销毁时调用 destroy() 方法,否则会导致内存泄漏
|
||||
*
|
||||
* @example
|
||||
* class MyClass extends EventDispatcher {
|
||||
* constructor() {
|
||||
* super();
|
||||
* this.on('myEvent', this.onMyEvent, this);
|
||||
* }
|
||||
*
|
||||
* onMyEvent(event: string, data: any) {
|
||||
* console.log('收到事件:', event, data);
|
||||
* }
|
||||
*
|
||||
* destroy() {
|
||||
* super.destroy(); // 清理所有事件监听
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
/** 批量注册、移除全局事件对象(用于组件级事件管理) */
|
||||
export class EventDispatcher {
|
||||
protected _msg: MessageEventData | null = null;
|
||||
/** 本地事件列表,用于批量清理 */
|
||||
private events: Map<string, Array<EventData>> = new Map();
|
||||
|
||||
/** 确保 MessageEventData 已初始化 */
|
||||
private ensureMessageEventData(): MessageEventData {
|
||||
if (this._msg == null) {
|
||||
this._msg = new MessageEventData();
|
||||
/**
|
||||
* 注册全局事件(强类型)
|
||||
* @param event 事件名(枚举)
|
||||
* @param listener 处理事件的侦听器函数
|
||||
* @param object 侦听函数绑定的作用域对象
|
||||
*/
|
||||
on<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
listener: (event: K, data: TypedEventMap[K]) => void,
|
||||
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);
|
||||
}
|
||||
return this._msg;
|
||||
|
||||
const ed: EventData = EventDataPool.get();
|
||||
ed.event = event;
|
||||
ed.listener = listener;
|
||||
ed.object = object;
|
||||
eds.push(ed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册全局事件
|
||||
* @param event 事件名
|
||||
* @param listener 处理事件的侦听器函数
|
||||
* 监听一次事件,事件响应后,该监听自动移除(强类型)
|
||||
* @param event 事件名(枚举)
|
||||
* @param listener 事件触发回调方法
|
||||
* @param object 侦听函数绑定的作用域对象
|
||||
*/
|
||||
on(event: string, listener: ListenerFunc, object: any) {
|
||||
this.ensureMessageEventData().on(event, listener, object);
|
||||
once<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
listener: (event: K, data: TypedEventMap[K]) => void,
|
||||
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 侦听函数绑定的作用域对象(可选)
|
||||
* 移除全局事件(强类型)
|
||||
* @param event 事件名(枚举)
|
||||
* @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器)
|
||||
* @param object 侦听函数绑定的作用域对象(可选)
|
||||
*/
|
||||
off(event: string, listener?: ListenerFunc, object?: any) {
|
||||
if (this._msg) {
|
||||
// 支持精确移除单个监听器
|
||||
if (listener) {
|
||||
this._msg.off(event, listener, object);
|
||||
} else {
|
||||
// 移除该事件的所有监听器
|
||||
this._msg.off(event);
|
||||
off<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
listener?: (event: K, data: TypedEventMap[K]) => void,
|
||||
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 data 事件数据(必须完全匹配类型定义)
|
||||
*/
|
||||
emit<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
data: TypedEventMap[K]
|
||||
): void {
|
||||
message.emit(event, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发全局事件(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param args 事件参数
|
||||
*/
|
||||
dispatchEvent(event: string, ...args: any) {
|
||||
this.ensureMessageEventData().dispatchEvent(event, ...args);
|
||||
|
||||
dispatchEvent(event: string, ...args: any[]): void {
|
||||
message.dispatchEvent(event, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁事件对象,释放所有事件监听
|
||||
* 触发强类型异步事件(严格类型检查)
|
||||
* @param event 事件名(枚举)
|
||||
* @param data 事件数据(必须完全匹配类型定义)
|
||||
*/
|
||||
destroy() {
|
||||
if (this._msg) {
|
||||
this._msg.clear();
|
||||
this._msg = null;
|
||||
emitAsync<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
data: TypedEventMap[K]
|
||||
): Promise<void> {
|
||||
return message.emitAsync(event, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发全局事件,支持同步与异步处理(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param args 事件参数
|
||||
*/
|
||||
|
||||
dispatchEventAsync(event: string, ...args: any[]): Promise<void> {
|
||||
return message.dispatchEventAsync(event, ...args);
|
||||
}
|
||||
|
||||
/** 清除所有的全局事件监听 */
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
import type { ListenerFunc } from './EventMessage';
|
||||
import type { TypedEventMap } from './MessageManager';
|
||||
import { EventData } from './EventData';
|
||||
import { EventDataPool } from './EventDataPool';
|
||||
import { message } from './MessageManager';
|
||||
|
||||
/** 批量注册、移除全局事件对象(用于组件级事件管理) */
|
||||
export class MessageEventData {
|
||||
/** 本地事件列表,用于批量清理 */
|
||||
private events: Map<string, Array<EventData>> = new Map();
|
||||
|
||||
/**
|
||||
* 注册全局事件(强类型重载)
|
||||
* @param event 事件名(枚举)
|
||||
* @param listener 处理事件的侦听器函数
|
||||
* @param object 侦听函数绑定的作用域对象
|
||||
*/
|
||||
on<K extends keyof TypedEventMap>(event: K, listener: (event: K, data: TypedEventMap[K]) => void, object: object): void;
|
||||
|
||||
/**
|
||||
* 注册全局事件(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param listener 处理事件的侦听器函数
|
||||
* @param object 侦听函数绑定的作用域对象
|
||||
*/
|
||||
on(event: string, listener: ListenerFunc, object: object): void;
|
||||
|
||||
/**
|
||||
* 注册全局事件(实现)
|
||||
*/
|
||||
on(event: string, listener: ListenerFunc, object: object) {
|
||||
// 先注册到全局消息管理器
|
||||
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 侦听函数绑定的作用域对象(可选)
|
||||
*/
|
||||
off<K extends keyof TypedEventMap>(event: K, listener?: (event: K, data: TypedEventMap[K]) => void, object?: object): void;
|
||||
|
||||
/**
|
||||
* 移除全局事件(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param listener 处理事件的侦听器函数(可选,不传则移除该事件的所有监听器)
|
||||
* @param object 侦听函数绑定的作用域对象(可选)
|
||||
*/
|
||||
off(event: string, listener?: ListenerFunc, object?: object): void;
|
||||
|
||||
/**
|
||||
* 移除全局事件(实现)
|
||||
*/
|
||||
off(event: string, listener?: ListenerFunc, object?: object) {
|
||||
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 data 事件数据
|
||||
*/
|
||||
dispatchEvent<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): void;
|
||||
|
||||
/**
|
||||
* 触发全局事件(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param args 事件参数
|
||||
*/
|
||||
|
||||
dispatchEvent(event: string, ...args: any[]): void;
|
||||
|
||||
/**
|
||||
* 触发全局事件(实现)
|
||||
*/
|
||||
|
||||
dispatchEvent(event: string, ...args: any[]) {
|
||||
message.dispatchEvent(event, ...args);
|
||||
}
|
||||
|
||||
/** 清除所有的全局事件监听 */
|
||||
clear() {
|
||||
// 直接遍历 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();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "35a44c13-f854-4219-8210-ff706c9d5b07",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import { EventDataPool } from './EventDataPool';
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
|
||||
export interface TypedEventMap {
|
||||
// 业务层通过 declare module 扩展此接口
|
||||
}
|
||||
@@ -32,55 +33,26 @@ export interface TypedEventMap {
|
||||
* ⚠️ 重要:组件销毁时必须调用 off() 移除事件监听,否则会导致内存泄漏
|
||||
* ⚠️ 建议:在 onDestroy() 或 destroy() 中移除所有注册的事件
|
||||
*
|
||||
* @强类型事件说明
|
||||
* - 使用 emit() 和 emitAsync() 方法可获得编译时的强类型约束
|
||||
* - 使用 dispatchEvent() 和 dispatchEventAsync() 兼容旧代码
|
||||
*
|
||||
* @help https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12037894&doc_id=2873565
|
||||
* @example
|
||||
// 注册持续监听的全局事件
|
||||
export class RoleViewComp extends Component{
|
||||
onLoad(){
|
||||
// 监听全局事件
|
||||
oops.message.on(GameEvent.GameServerConnected, this.onHandler, this);
|
||||
}
|
||||
|
||||
protected onDestroy() {
|
||||
// 对象释放时取消注册的全局事件
|
||||
oops.message.off(GameEvent.GameServerConnected, this.onHandler, this);
|
||||
}
|
||||
|
||||
private onHandler(event: string, args: any) {
|
||||
switch (event) {
|
||||
case GameEvent.GameServerConnected:
|
||||
console.log("处理游戏服务器连接成功后的逻辑");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册只触发一次的全局事件
|
||||
export class RoleViewComp extends Component{
|
||||
onLoad(){
|
||||
// 监听一次事件,事件响应后,该监听自动移除
|
||||
oops.message.once(GameEvent.GameServerConnected, this.onHandler, this);
|
||||
}
|
||||
|
||||
private onHandler(event: string, args: any) {
|
||||
switch (event) {
|
||||
case GameEvent.GameServerConnected:
|
||||
console.log("处理游戏服务器连接成功后的逻辑");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
export class MessageManager {
|
||||
private events: Map<string, Array<EventData>> = new Map();
|
||||
|
||||
/**
|
||||
* 注册全局事件(强类型重载)
|
||||
* 注册全局事件(强类型)
|
||||
* @param event 事件名(枚举)
|
||||
* @param listener 处理事件的侦听器函数
|
||||
* @param object 侦听函数绑定的作用域对象
|
||||
*/
|
||||
on<K extends keyof TypedEventMap>(event: K, listener: (event: K, data: TypedEventMap[K]) => void, object: object): void;
|
||||
on<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
listener: (event: K, data: TypedEventMap[K]) => void,
|
||||
object: object
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 注册全局事件(兼容旧用法)
|
||||
@@ -93,7 +65,7 @@ export class MessageManager {
|
||||
/**
|
||||
* 注册全局事件(实现)
|
||||
*/
|
||||
on(event: string, listener: ListenerFunc, object: object) {
|
||||
on(event: string, listener: ListenerFunc, object: object): void {
|
||||
if (!event || !listener) {
|
||||
warn(`注册【${event}】事件的侦听器函数为空`);
|
||||
return;
|
||||
@@ -124,12 +96,16 @@ export class MessageManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听一次事件,事件响应后,该监听自动移除(强类型重载)
|
||||
* 监听一次事件,事件响应后,该监听自动移除(强类型)
|
||||
* @param event 事件名(枚举)
|
||||
* @param listener 事件触发回调方法
|
||||
* @param object 侦听函数绑定的作用域对象
|
||||
*/
|
||||
once<K extends keyof TypedEventMap>(event: K, listener: (event: K, data: TypedEventMap[K]) => void, object: object): void;
|
||||
once<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
listener: (event: K, data: TypedEventMap[K]) => void,
|
||||
object: object
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 监听一次事件,事件响应后,该监听自动移除(兼容旧用法)
|
||||
@@ -142,17 +118,17 @@ export class MessageManager {
|
||||
/**
|
||||
* 监听一次事件,事件响应后,该监听自动移除(实现)
|
||||
*/
|
||||
once(event: string, listener: ListenerFunc, object: 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 侦听函数绑定的作用域对象(可选)
|
||||
@@ -174,7 +150,7 @@ export class MessageManager {
|
||||
/**
|
||||
* 移除全局事件(实现)
|
||||
*/
|
||||
off(event: string, listener?: Function, object?: object) {
|
||||
off(event: string, listener?: Function, object?: object): void {
|
||||
const eds = this.events.get(event);
|
||||
|
||||
if (!eds) {
|
||||
@@ -207,17 +183,6 @@ export class MessageManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发全局事件(强类型重载)
|
||||
* @param event 事件名(枚举)
|
||||
* @param data 事件数据
|
||||
* @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历
|
||||
*/
|
||||
dispatchEvent<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
data: TypedEventMap[K]
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 触发全局事件(兼容旧用法)
|
||||
* @param event 事件名
|
||||
@@ -225,16 +190,9 @@ export class MessageManager {
|
||||
* @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历
|
||||
*/
|
||||
|
||||
dispatchEvent(event: string, ...args: any[]): void;
|
||||
|
||||
/**
|
||||
* 触发全局事件(实现)
|
||||
*/
|
||||
|
||||
dispatchEvent(event: string, ...args: any[]) {
|
||||
dispatchEvent(event: string, ...args: any[]): void {
|
||||
const list = this.events.get(event);
|
||||
if (list != null) {
|
||||
// 创建副本以支持在回调中安全地修改监听器列表
|
||||
const eds: Array<EventData> = list.concat();
|
||||
const length = eds.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
@@ -244,40 +202,17 @@ export class MessageManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发全局事件,支持同步与异步处理(强类型重载)
|
||||
* @param event 事件名(枚举)
|
||||
* @param data 事件数据
|
||||
* @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历
|
||||
*/
|
||||
dispatchEventAsync<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): Promise<void>;
|
||||
|
||||
/**
|
||||
* 触发全局事件,支持同步与异步处理(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param args 事件参数
|
||||
* @note 使用 concat() 创建数组副本,防止在事件回调中添加/删除监听器时影响遍历
|
||||
* @example 事件响应示例
|
||||
onTest(event: string, args: any): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
console.log("异步事逻辑");
|
||||
resolve();
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
*/
|
||||
dispatchEventAsync(event: string, ...args: any[]): Promise<void>;
|
||||
|
||||
/**
|
||||
* 触发全局事件,支持同步与异步处理(实现)
|
||||
*/
|
||||
|
||||
dispatchEventAsync(event: string, ...args: any[]): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const list = this.events.get(event);
|
||||
if (list != null) {
|
||||
// 创建副本以支持在回调中安全地修改监听器列表
|
||||
const eds: Array<EventData> = list.concat();
|
||||
const length = eds.length;
|
||||
(async () => {
|
||||
@@ -293,6 +228,50 @@ export class MessageManager {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发强类型事件(严格类型检查)
|
||||
* @param event 事件名(枚举)
|
||||
* @param data 事件数据(必须完全匹配类型定义)
|
||||
* @note 使用此方法可获得编译时的强类型约束,参数不匹配会编译报错
|
||||
*/
|
||||
emit<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): void {
|
||||
const list = this.events.get(event as string);
|
||||
if (list != null) {
|
||||
const eds: Array<EventData> = list.concat();
|
||||
const length = eds.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const ed = eds[i];
|
||||
ed.listener.call(ed.object, event, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发强类型异步事件(严格类型检查)
|
||||
* @param event 事件名(枚举)
|
||||
* @param data 事件数据(必须完全匹配类型定义)
|
||||
* @note 使用此方法可获得编译时的强类型约束,参数不匹配会编译报错
|
||||
*/
|
||||
emitAsync<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const list = this.events.get(event as string);
|
||||
if (list != null) {
|
||||
const eds: Array<EventData> = 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, data));
|
||||
}
|
||||
resolve();
|
||||
})();
|
||||
}
|
||||
else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const message = new MessageManager();
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { IAudioParams } from '../../core/common/audio/IAudio';
|
||||
import { EventDispatcher } from '../../core/common/event/EventDispatcher';
|
||||
import type { ListenerFunc } from '../../core/common/event/EventMessage';
|
||||
import { EventMessage } from '../../core/common/event/EventMessage';
|
||||
import type { TypedEventMap } from '../../core/common/event/MessageManager';
|
||||
import type { AssetType, CompleteCallback, Paths, ProgressCallback } from '../../core/common/loader/ResLoader';
|
||||
import { resLoader } from '../../core/common/loader/ResLoader';
|
||||
import { ViewUtil } from '../../core/utils/ViewUtil';
|
||||
@@ -52,31 +53,115 @@ export class GameComponent extends Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册全局事件
|
||||
* 注册全局事件(强类型)
|
||||
* @param event 事件名(枚举)
|
||||
* @param listener 处理事件的侦听器函数
|
||||
* @param object 侦听函数绑定的this对象
|
||||
*/
|
||||
on<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
listener: (event: K, data: TypedEventMap[K]) => void,
|
||||
object: any
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 注册全局事件(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param listener 处理事件的侦听器函数
|
||||
* @param object 侦听函数绑定的this对象
|
||||
*/
|
||||
on(event: string, listener: ListenerFunc, object: any) {
|
||||
on(event: string, listener: ListenerFunc, object: any): void;
|
||||
|
||||
/**
|
||||
* 注册全局事件(实现)
|
||||
*/
|
||||
on(event: string, listener: ListenerFunc, object: any): void {
|
||||
this.event.on(event, listener, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除全局事件
|
||||
* 监听一次事件,事件响应后,该监听自动移除(强类型)
|
||||
* @param event 事件名(枚举)
|
||||
* @param listener 事件触发回调方法
|
||||
* @param object 侦听函数绑定的this对象
|
||||
*/
|
||||
once<K extends keyof TypedEventMap>(
|
||||
event: K,
|
||||
listener: (event: K, data: TypedEventMap[K]) => void,
|
||||
object: any
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 监听一次事件,事件响应后,该监听自动移除(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param listener 事件触发回调方法
|
||||
* @param object 侦听函数绑定的this对象
|
||||
*/
|
||||
once(event: string, listener: ListenerFunc, object: any): void;
|
||||
|
||||
/**
|
||||
* 监听一次事件,事件响应后,该监听自动移除(实现)
|
||||
*/
|
||||
once(event: string, listener: ListenerFunc, object: any): void {
|
||||
this.event.once(event, listener, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除全局事件(强类型)
|
||||
* @param event 事件名(枚举)
|
||||
*/
|
||||
off<K extends keyof TypedEventMap>(event: K): void;
|
||||
|
||||
/**
|
||||
* 移除全局事件(兼容旧用法)
|
||||
* @param event 事件名
|
||||
*/
|
||||
off(event: string) {
|
||||
off(event: string): void;
|
||||
|
||||
/**
|
||||
* 移除全局事件(实现)
|
||||
*/
|
||||
off(event: string): void {
|
||||
this.event.off(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发全局事件
|
||||
* 触发强类型全局事件
|
||||
* @param event 事件名(枚举)
|
||||
* @param data 事件数据
|
||||
*/
|
||||
emit<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): void {
|
||||
this.event.emit(event, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发全局事件(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param args 事件参数
|
||||
*/
|
||||
dispatchEvent(event: string, ...args: any) {
|
||||
|
||||
dispatchEvent(event: string, ...args: any[]): void {
|
||||
this.event.dispatchEvent(event, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发强类型异步全局事件(严格类型检查)
|
||||
* @param event 事件名(枚举)
|
||||
* @param data 事件数据(必须完全匹配类型定义)
|
||||
*/
|
||||
emitAsync<K extends keyof TypedEventMap>(event: K, data: TypedEventMap[K]): Promise<void> {
|
||||
return this.event.emitAsync(event, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发全局事件,支持同步与异步处理(兼容旧用法)
|
||||
* @param event 事件名
|
||||
* @param args 事件参数
|
||||
*/
|
||||
|
||||
dispatchEventAsync(event: string, ...args: any[]): Promise<void> {
|
||||
return this.event.dispatchEventAsync(event, ...args);
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region 预制节点管理
|
||||
@@ -248,12 +333,12 @@ export class GameComponent extends Component {
|
||||
* @param bundleName 资源包名
|
||||
* @param releaseAll 是否释放所有引用计数(默认只释放一次)
|
||||
*/
|
||||
releaseRes(path: string, bundleName: string = resLoader.defaultBundleName, releaseAll: boolean = false) {
|
||||
releaseRes(path: string, bundleName: string = resLoader.defaultBundleName, releaseAll = false) {
|
||||
if (!this.resPaths) return;
|
||||
|
||||
|
||||
const rps = this.resPaths.get(ResType.Load);
|
||||
if (!rps) return;
|
||||
|
||||
|
||||
const key = this.getResKey(bundleName, path);
|
||||
const record = rps.get(key);
|
||||
if (record) {
|
||||
@@ -317,10 +402,10 @@ export class GameComponent extends Component {
|
||||
*/
|
||||
getResRefCount(path: string, bundleName: string = resLoader.defaultBundleName): number {
|
||||
if (!this.resPaths) return 0;
|
||||
|
||||
|
||||
const rps = this.resPaths.get(ResType.Load);
|
||||
if (!rps) return 0;
|
||||
|
||||
|
||||
const key = this.getResKey(bundleName, path);
|
||||
const record = rps.get(key);
|
||||
return record ? record.refCount : 0;
|
||||
@@ -333,14 +418,14 @@ export class GameComponent extends Component {
|
||||
getAllResRecords(): ResRecord[] {
|
||||
const records: ResRecord[] = [];
|
||||
if (!this.resPaths) return records;
|
||||
|
||||
|
||||
const rps = this.resPaths.get(ResType.Load);
|
||||
if (rps) {
|
||||
rps.forEach((value: ResRecord) => {
|
||||
records.push({ ...value });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
@@ -352,27 +437,27 @@ export class GameComponent extends Component {
|
||||
console.log('[资源管理] 暂无资源记录');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const loadRps = this.resPaths.get(ResType.Load);
|
||||
const dirRps = this.resPaths.get(ResType.LoadDir);
|
||||
|
||||
|
||||
console.log('========== 资源使用情况 ==========');
|
||||
console.log(`组件: ${this.node.name}`);
|
||||
|
||||
|
||||
if (loadRps && loadRps.size > 0) {
|
||||
console.log(`\n[普通资源] 共 ${loadRps.size} 个:`);
|
||||
loadRps.forEach((value: ResRecord, key: string) => {
|
||||
console.log(` - ${key} (引用计数: ${value.refCount})`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (dirRps && dirRps.size > 0) {
|
||||
console.log(`\n[文件夹资源] 共 ${dirRps.size} 个:`);
|
||||
dirRps.forEach((value: ResRecord, key: string) => {
|
||||
console.log(` - ${key} (引用计数: ${value.refCount})`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
console.log('==================================');
|
||||
}
|
||||
|
||||
@@ -393,13 +478,13 @@ export class GameComponent extends Component {
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 释放旧的 spriteFrame 引用,避免内存泄漏
|
||||
const oldSpriteFrame = target.spriteFrame;
|
||||
if (oldSpriteFrame && isValid(oldSpriteFrame)) {
|
||||
oldSpriteFrame.decRef();
|
||||
}
|
||||
|
||||
|
||||
// 增加新 spriteFrame 引用并设置
|
||||
spriteFrame.addRef();
|
||||
target.spriteFrame = spriteFrame;
|
||||
@@ -430,10 +515,10 @@ export class GameComponent extends Component {
|
||||
else if (params.bundle == null) {
|
||||
params.bundle = resLoader.defaultBundleName;
|
||||
}
|
||||
|
||||
|
||||
const bundle = params.bundle || resLoader.defaultBundleName;
|
||||
const ae = await oops.audio.playEffect(url, params);
|
||||
|
||||
|
||||
if (ae) {
|
||||
// 音效加载成功,记录资源引用
|
||||
this.addPathToRecord(ResType.Load, bundle, url);
|
||||
@@ -588,7 +673,7 @@ export class GameComponent extends Component {
|
||||
protected onDestroy() {
|
||||
// 释放消息对象
|
||||
if (this._event) {
|
||||
this._event.destroy();
|
||||
this._event.clear();
|
||||
this._event = null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user