前言
在程序开发中,经常会用到事件监听发射机制,方便在不同的脚本之间传递信息,按需监听,避免了脚本之间过多的关联,提高效率,无形中达到了解耦的效果。
本文将带着大家从 0 实现一个事件监听发射系统,让我们开始吧。
正文
整体思路
代码实现
提示:点击文章底部 阅读原文 即可获取完整文件
1. 定义 订阅 ISubscription 的结构:
interface ISubscription {
callback: Function;
object: any;
}
2. 定义 事件容器 IEvents 的结构(key 为字符串类型的事件名,value 则为 订阅 类型的数组):
interface IEvents {
[event: string]: ISubscription[];
}
3. 定义 GameEvent 类和 事件容器 类型的变量:
export class GameEvent {
private static events: IEvents = {};
}
4. 实现监听函数 on ,需要传入的参数为事件名、回调和调用对象(可选,当回调为箭头函数时可以不传入此参数);当容器中不存在目标事件时,需先创建事件,这里我没有进行重复检测,有需要可以自行加入:
/**
* 监听事件
* @param event 事件名
* @param callback 回调
* @param object 监听对象
*/
public static on(event: string, callback: Function, object?: any) {
if (!this.events[event]) this.events[event] = [];
this.events[event].push({ callback, object });
}
5. 实现发射函数 emit ,需要传入的参数为事件名以及若干参数;没有目标事件直接返回,否则遍历所有订阅并调用:
/**
* 发射事件
* @param event 事件名
* @param args 参数
*/
public static emit(event: string, ...args: any[]) {
if (!this.events[event]) return;
for (let i = 0; i < this.events[event].length; i++) {
this.events[event][i].callback.apply(this.events[event][i].object, args);
}
}
6. 实现取消监听函数 off ,需传入与函数 on 同样的参数;存在目标事件时遍历所有订阅,除去相应订阅:
/**
* 取消监听事件
* @param event 事件名
* @param callback 回调
* @param object 监听对象
*/
public static off(event: string, callback: Function, object?: any) {
if (!this.events[event]) return;
for (let i = 0; i < this.events[event].length; i++) {
if (this.events[event][i].callback === callback && (!object || this.events[event][i].object === object)) {
this.events[event].splice(i, 1);
i--;
}
}
}
7. 实现清除事件函数 remove :
/**
* 移除事件
* @param event 事件名
*/
public static remove(event: string) {
if (this.events[event]) delete this.events[event];
}
8. 另外还可以实现一次性的监听事件 once ,只需在调用一次后移除即可,具体逻辑本文不再赘述。
使用示例
import { GameEvent } from "../../eazax-ccc/core/GameEvent";
const { ccclass, property } = cc._decorator;
@ccclass
export default class Test extends cc.Component {
onLoad() {
// 监听事件
GameEvent.on('init', this.init, this);
GameEvent.on('init', (param: any) => { this.init(param) });
// 发射事件
GameEvent.emit('init', 666);
}
private init(param: any) {
cc.log(param);
}
onDestroy() {
// 取消监听
GameEvent.off('init', this.init, this);
GameEvent.off('init', (param: any) => { this.init(param) });
// 清除事件
GameEvent.remove('init');
}
}
结束语
以上皆为本菜鸡的个人观点,文采实在不太好,如果写得不好还请各位见谅。如果有哪些地方说的不对,还请各位指出,大家共同进步。