【Laya】Delegate 使用说明
Laya.Delegate 是 LayaAir 引擎中的委托类,用于管理多个回调函数的注册和触发。它提供添加(add)、移除(remove)、触发(invoke)等基本方法,支持一次性回调(once)和带预定义参数的调用。本文介绍了 Laya.Delegate 的基本用法,包括创建实例、添加/移除回调、触发事件等操作,并提供了多个实用示例,如基础委托使用、一次性回调、带参数回调以及事件管理器实现。
·
Laya.Delegate 使用说明
简介
Laya.Delegate 是 LayaAir 引擎中的委托类,用于管理多个回调函数的注册、移除和触发。它提供了一种灵活的事件处理机制,允许将多个监听器绑定到同一个事件上。
核心特性:
- 多监听器支持:同一个委托可以注册多个回调函数
- target 管理:通过 target 参数管理回调的所有者
- 一次性回调:支持触发后自动移除的回调
- 批量清理:支持按 target 清理所有相关回调
与 EventDispatcher 的区别:
| 特性 | Laya.Delegate | Laya.EventDispatcher |
|---|---|---|
| 事件类型 | 无类型区分 | 支持多种事件类型 |
| 监听器数量 | 支持多个 | 每种事件类型支持多个 |
| 典型场景 | 自定义回调管理 | UI交互、系统事件 |
目录
API 参考
添加回调
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
add(callback, target?, args?) |
回调函数, 目标对象, 预设参数 | void |
添加回调函数 |
once(callback, target?, args?) |
回调函数, 目标对象, 预设参数 | void |
添加一次性回调,触发后自动移除 |
移除回调
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
remove(callback, target?) |
回调函数, 目标对象 | void |
移除指定的回调函数 |
触发委托
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
invoke(...args) |
可变参数 | void |
触发所有已注册的回调函数 |
清理委托
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
clear() |
无 | void |
清空所有回调函数 |
clearForTarget(target) |
目标对象 | void |
清空指定 target 的所有回调 |
属性
| 属性 | 类型 | 说明 |
|---|---|---|
count |
number |
获取当前已注册的回调函数数量 |
基础用法
1. 创建委托实例
// 创建委托
const myDelegate = new Laya.Delegate();
2. 添加回调
// 添加简单回调
myDelegate.add((data: string) => {
console.log("收到数据:", data);
});
// 带 target 的方式(推荐)
class GameManager {
public onEvent(data: string): void {
console.log("处理事件:", data);
}
}
const manager = new GameManager();
myDelegate.add(manager.onEvent, manager);
3. 触发委托
// 触发所有回调
myDelegate.invoke("Hello World");
// 传递多个参数
myDelegate.invoke("Player", 100, true);
4. 移除回调
// 移除特定回调
myDelegate.remove(callbackFunction);
// 带 target 的移除
myDelegate.remove(manager.onEvent, manager);
5. 清理委托
// 清空所有回调
myDelegate.clear();
// 清空指定 target 的所有回调
myDelegate.clearForTarget(manager);
6. 查看回调数量
console.log("当前回调数量:", myDelegate.count);
实用示例
示例1: 异步任务管理
@regClass()
export class TaskManager extends Laya.Script {
private onComplete: Laya.Delegate;
private onProgress: Laya.Delegate;
onAwake(): void {
this.onComplete = new Laya.Delegate();
this.onProgress = new Laya.Delegate();
// 注册监听器
this.onComplete.add(this.handleComplete, this);
this.onProgress.add(this.handleProgress, this);
}
public loadResource(): void {
let progress = 0;
const timer = setInterval(() => {
progress += 20;
this.onProgress.invoke(progress);
if (progress >= 100) {
clearInterval(timer);
this.onComplete.invoke();
}
}, 500);
}
private handleProgress(value: number): void {
console.log("加载进度:", value + "%");
}
private handleComplete(): void {
console.log("加载完成!");
}
onDestroy(): void {
this.onComplete.clear();
this.onProgress.clear();
}
}
示例2: 一次性回调
@regClass()
export class OneTimeEvent extends Laya.Script {
private eventDelegate: Laya.Delegate;
onAwake(): void {
this.eventDelegate = new Laya.Delegate();
// 添加一次性回调
this.eventDelegate.once(() => {
console.log("首次触发");
});
// 第一次触发 - 会执行
this.eventDelegate.invoke();
console.log("回调数量:", this.eventDelegate.count); // 0
// 第二次触发 - 不会执行
this.eventDelegate.invoke();
}
}
示例3: 带预设参数的回调
@regClass()
export class ButtonGroup extends Laya.Script {
private clickDelegate: Laya.Delegate;
onAwake(): void {
this.clickDelegate = new Laya.Delegate();
// 添加带预设参数的回调
this.clickDelegate.add(
this.onButtonClick,
this,
["button_001", "预设信息"]
);
}
public triggerClick(): void {
// 不传递参数,使用预设参数
this.clickDelegate.invoke();
}
private onButtonClick(buttonId: string, extra: string): void {
console.log(`点击了: ${buttonId}, ${extra}`);
}
}
示例4: 事件管理器
export class EventManager {
private static instance: EventManager;
private events: Map<string, Laya.Delegate>;
private constructor() {
this.events = new Map();
}
public static getInstance(): EventManager {
if (!EventManager.instance) {
EventManager.instance = new EventManager();
}
return EventManager.instance;
}
public on(eventName: string, callback: Function, target?: any): void {
if (!this.events.has(eventName)) {
this.events.set(eventName, new Laya.Delegate());
}
this.events.get(eventName).add(callback, target);
}
public once(eventName: string, callback: Function, target?: any): void {
if (!this.events.has(eventName)) {
this.events.set(eventName, new Laya.Delegate());
}
this.events.get(eventName).once(callback, target);
}
public off(eventName: string, callback: Function, target?: any): void {
const delegate = this.events.get(eventName);
if (delegate) {
delegate.remove(callback, target);
}
}
public emit(eventName: string, ...args: any[]): void {
const delegate = this.events.get(eventName);
if (delegate) {
delegate.invoke(...args);
}
}
public offAllTarget(target: any): void {
this.events.forEach((delegate) => {
delegate.clearForTarget(target);
});
}
public clear(): void {
this.events.forEach((delegate) => delegate.clear());
this.events.clear();
}
}
// 使用示例
@regClass()
export class Player extends Laya.Script {
private name: string;
constructor(name: string) {
super();
this.name = name;
}
public onPlayerDie(reason: string): void {
console.log(`${this.name} 死亡: ${reason}`);
}
}
@regClass()
export class GameMain extends Laya.Script {
private eventManager: EventManager;
private players: Player[] = [];
onAwake(): void {
this.eventManager = EventManager.getInstance();
// 创建玩家
this.players.push(new Player("张三") as any);
this.players.push(new Player("李四") as any);
// 注册事件
this.eventManager.on("playerDie", this.players[0].onPlayerDie, this.players[0]);
this.eventManager.on("playerDie", this.players[1].onPlayerDie, this.players[1]);
}
public killPlayer(index: number): void {
this.eventManager.emit("playerDie", "中毒");
}
public removePlayer(index: number): void {
const player = this.players[index];
this.eventManager.offAllTarget(player);
}
}
示例5: 可观察属性
@regClass()
export class ObservableValue extends Laya.Script {
private _value: number;
private onChange: Laya.Delegate;
onAwake(): void {
this._value = 0;
this.onChange = new Laya.Delegate();
}
public get value(): number {
return this._value;
}
public set value(v: number) {
if (this._value !== v) {
this._value = v;
this.onChange.invoke(v);
}
}
public watch(callback: (value: number) => void, target?: any): void {
this.onChange.add(callback, target);
}
}
// 使用
@regClass()
export class UIController extends Laya.Script {
declare owner: Laya.Sprite;
private healthValue: ObservableValue;
onAwake(): void {
this.healthValue = new ObservableValue();
// 监听值变化
this.healthValue.watch((value: number) => {
console.log("血量变化:", value);
this.updateHPBar(value);
}, this);
}
private updateHPBar(value: number): void {
// 更新血条显示
}
public setHealth(value: number): void {
this.healthValue.value = value;
}
}
高级技巧
1. 链式调用
// Delegate 方法不返回 this,不支持链式调用
// ❌ 错误
myDelegate.add(cb1).add(cb2);
// ✅ 正确
myDelegate.add(cb1);
myDelegate.add(cb2);
2. 条件移除
class CallbackManager {
private callbacks: Function[] = [];
public add(callback: Function): void {
this.callbacks.push(callback);
}
public remove(callback: Function): void {
const index = this.callbacks.indexOf(callback);
if (index !== -1) {
this.callbacks.splice(index, 1);
}
}
}
3. 动态参数组合
@regClass()
export class DynamicArgs extends Laya.Script {
private delegate: Laya.Delegate;
onAwake(): void {
this.delegate = new Laya.Delegate();
// 预设参数 + invoke 参数组合
this.delegate.add(
(preset: string, dynamic: number) => {
console.log(`预设: ${preset}, 动态: ${dynamic}`);
},
this,
["预设值"]
);
}
public trigger(value: number): void {
// 预设参数会自动传递
this.delegate.invoke(value);
}
}
4. 防抖委托
@regClass()
export class DebounceDelegate extends Laya.Script {
private delegate: Laya.Delegate;
private timer: number = null;
private delay: number = 300;
constructor(delay: number = 300) {
super();
this.delay = delay;
this.delegate = new Laya.Delegate();
}
public add(callback: Function, target?: any): void {
this.delegate.add(callback, target);
}
public invoke(...args: any[]): void {
if (this.timer !== null) {
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
this.delegate.invoke(...args);
this.timer = null;
}, this.delay);
}
public destroy(): void {
if (this.timer !== null) {
clearTimeout(this.timer);
}
this.delegate.clear();
}
}
最佳实践
1. 始终使用 target 参数
// ✅ 推荐:可以正确移除
myDelegate.add(this.onCallback, this);
myDelegate.remove(this.onCallback, this);
// ❌ 不推荐:移除可能失败
myDelegate.add(this.onCallback);
myDelegate.remove(this.onCallback);
2. 及时清理委托
@regClass()
export class MyComponent extends Laya.Script {
private delegate: Laya.Delegate;
onAwake(): void {
this.delegate = new Laya.Delegate();
this.delegate.add(this.onCallback, this);
}
onDestroy(): void {
// ✅ 推荐:清理委托
this.delegate.clear();
this.delegate = null;
// ❌ 避免:忘记清理
}
}
3. 使用一次性回调简化代码
// ❌ 不推荐:手动移除
this.delegate.add(this.onFirstClick, this);
// ...回调中手动移除
private onFirstClick(): void {
this.delegate.remove(this.onFirstClick, this);
}
// ✅ 推荐:使用 once
this.delegate.once(this.onFirstClick, this);
4. 避免循环引用
@regClass()
export class SafeDelegate extends Laya.Script {
private delegate: Laya.Delegate;
onAwake(): void {
this.delegate = new Laya.Delegate();
this.delegate.add(this.onCallback, this);
}
private onCallback(): void {
// ✅ 安全:不持有外部引用
console.log("Callback");
}
onDestroy(): void {
// 清理委托,释放引用
this.delegate.clear();
}
}
5. 委托链管理
export class DelegateChain {
private delegates: Laya.Delegate[] = [];
public add(delegate: Laya.Delegate): void {
this.delegates.push(delegate);
}
public invoke(...args: any[]): void {
this.delegates.forEach(delegate => {
delegate.invoke(...args);
});
}
public clear(): void {
this.delegates.forEach(delegate => delegate.clear());
this.delegates = [];
}
}
6. 条件回调
@regClass()
export class ConditionalDelegate extends Laya.Script {
private delegate: Laya.Delegate;
private condition: () => boolean;
constructor(condition: () => boolean) {
super();
this.delegate = new Laya.Delegate();
this.condition = condition;
}
public add(callback: Function, target?: any): void {
this.delegate.add(callback, target);
}
public invoke(...args: any[]): void {
if (this.condition()) {
this.delegate.invoke(...args);
}
}
public clear(): void {
this.delegate.clear();
}
}
注意事项
- target 参数:强烈建议添加时传入 target,便于后续管理和移除
- 内存泄漏:使用完毕后必须清理委托,避免内存泄漏
- 重复添加:同一个回调可以重复添加,会被多次调用
- 执行顺序:回调按照添加顺序依次执行
- 异常处理:一个回调中的异常不会影响其他回调的执行
- 线程安全:回调在同一线程中同步执行
相关文档
更多推荐


所有评论(0)