使用场景
H5游戏开发,跨JS文件事件监听及派发,游戏引擎cocoscreator v2.4.2,开发语言JavaScript。
代码实现
/**
* 事件派发机制 EventListener.js @半世 2021/05/25
*/
const EventListener = {
//事件表
Regsiter: {},
//注册事件
on: function(name, method){
if(!this.Regsiter.hasOwnProperty(name)){
this.Regsiter[name] = [];
}
this.Regsiter[name].push(method);
},
//触发事件
fire: function(name){
if(this.Regsiter.hasOwnProperty(name)){
let handlerList = this.Regsiter[name];
//遍历回调函数列表(同一个事件,多个回调监听)
for(let i = 0; i < handlerList.length; ++i){
let handler = handlerList[i];
let args = [];
//参数处理
for(let j = 1; j < arguments.length; ++j){
args.push(arguments[j]);
}
//调用事件回调
handler.apply(this, args);
}
}
},
//注销事件
off: function(name, method){
if(this.Regsiter.hasOwnProperty(name)){
//同一个事件,可能会触发多个处理函数,所以,在注册时以数组的形式存储事件,销毁时,亦同。
let handlerList = this.Regsiter[name];
for(let i = 0; i < handlerList.length; ++i){
console.log('循环查找某个事件进行注销', i, (handlerList[i]===method));
if(handlerList[i] === method){
console.log('注销成功')
handlerList.splice(i , 1);
}
}
}
}
};
module.exports = EventListener;
代码解析
上方代码有两个重点:
1、函数的 arguments 隐藏参数,函数在声明的时候,都会自带一个 arguments 属性,里面以数组的形式存放该函数在被调用时,所传递过来的参数。所以,我们再处理 fire 函数的时候,可以通过该属性,拿取传递过来的各种参数。
2、JS的 apply() 方法,简单来讲,该方法就是用来改变当前代码运行环境的 this 指向。具体可以看我的另一篇文档。JavaScript 中 call()、apply()、bind() 的用法
注册监听事件
/**
* 游戏主逻辑控制类 GameManager.js @半世 2021/05/21
*/
let EventListener = require('../event/EventListener');
cc.Class({
extends: cc.Component,
properties: {
},
// LIFE-CYCLE CALLBACKS:
// cocoscreator 自带的声明周期函数 onLoad() 我比较习惯于在这里做一些初始化工作以及事件监听
onLoad () {
//正确绑定
this.test_event_callback = this.showPanelGameOver.bind(this);
EventListener.on('test_event', this.test_event_callback);
//错误绑定
EventListener.on('test_event2', this.showPanelGameOver.bind(this));
},
// start() {},
eventOff(){
//正确销毁
EventListener.off('test_event', this.test_event_callback);
//错误销毁
EventListener.off('test_event2', this.test_event_callback.bind(this));
},
// update (dt) {},
});
代码解析
上面有一个两个重点:
1、bind() 方法的使用,函数 bind 之后,返回值是一个函数,需要用个变量存储一下,否则后面销毁的时候,你再次通过 bind 形式去销毁,销毁的是另外一个函数了, 事件监听表里面是找不到这个新生成的函数的。
2、函数的比较,事件在销毁的时候会进行函数 === 判断。这里判断两个函数是否相等,是通过比较两个函数的指针,所指向的地址(栈地址)是否为同一个地址。
触发事件
/**
* 游戏主界面逻辑控制类 PanelMain.js @半世 2021/05/21
*/
let EventListener = require('../event/EventListener');
cc.Class({
extends: cc.Component,
properties: {
},
// LIFE-CYCLE CALLBACKS:
// onLoad () {},
//声明周期函数
start() {
//触发事件
EventListener.fire('test_event', 'a', 'b', 10086);
},
// update (dt) {},
});
备注:事件监听机制是开发过程中十分常用的一个机制,代码量虽然不大,但涉及到的小知识点挺多的。关于 JS 的 this 绑定,以及模块的导出和导入,可以参考一下我的其他帖子。
JavaScript 中 call()、apply()、bind() 的用法
node.js模块化(module.exports/exports/require)
至此,结束。