摘要
CocosCreator 有着内置的事件系统,我们用起来也很是方便。那么我们自己如何简单的实现一个 EventManager 呢?KUOKUO 通过一个小例子带你学习。
正文
使用版本
CocosCreator 版本 2.2.2
明确目标
我们要做一个事件管理模块,实现事件的监听方法 on,取消方法 off,事件发送 emit。
事件数据类型
首先,我们要想好事件用什么存储。选择用 Map,则需要一个事件名称,类型 string,还有就是一个对象,存放 callback 以及调用者 target。让我们规定一下类型:
-
/** 事件数据接口 */
-
interface EventData {
-
callback: Function,
-
target: any
-
}
存储Map
让我们写出类的名称:
-
export class EventManager {
-
}
声明其私有的 Map:
-
private eventsMap: Map<string, EventData> = new Map()
存入事件
on 的实现就是将传入的参数进行存储,如果这个事件已经有了,就覆盖掉:
-
public on (eventName: string, callback: Function, target: any) {
-
if (this.eventsMap.has(eventName)) {
-
console.warn(`${eventName} 事件已存在,覆盖`)
-
}
-
this.eventsMap.set(eventName, { callback, target })
-
}
与之对应的取消监听,就是将事件从 Map 中删除:
-
public off (eventName: string) {
-
if (!this.eventsMap.has(eventName)) {
-
console.warn(`${eventName} 事件不存在`)
-
return
-
}
-
this.eventsMap.delete(eventName)
-
}
事件的发送
最重要的一步是事件的发送,我们首先要取到 Map 中对应的事件,然后利用 call 或者 apply 使其在 target 的作用域下被调用(使用箭头函数会使得这个 target 无效,会指向声明时的 this)。
-
public emit (eventName: string, data: any) {
-
if (!this.eventsMap.has(eventName)) {
-
console.warn(`${eventName} 事件不存在`)
-
return
-
}
-
const { callback, target } = this.eventsMap.get(eventName)
-
/** 执行回调 */
-
callback.call(target, data)
-
}
data 参数可以拓展多个,但是实际上用对象包住,一个也是可以的,比如测试代码:
-
this.eventManager.emit('event1', { data1: 'kuokuo', data2: [6, 6, 6] })
实际测试
写一个测试脚本,里面做两个事件监听,新建两个按钮,分别绑定到脚本中的 onClick 方法:
-
import { EventManager } from "./EventManager"
-
const {ccclass, property} = cc._decorator
-
-
@ccclass
-
export default class Test extends cc.Component {
-
-
eventManager: EventManager = new EventManager()
-
-
onLoad () {
-
// 监听事件1
-
this.eventManager.on('event1', (data) => {
-
console.log('事件1触发,数据为:')
-
console.log(data)
-
}, this)
-
// 监听事件2
-
this.eventManager.on('event2', (data) => {
-
console.log('事件2触发,数据为:')
-
console.log(data)
-
}, this)
-
}
-
-
onClick_1 () {
-
this.eventManager.emit('event1', { data1: 'kuokuo', data2: [6, 6, 6] })
-
}
-
-
onClick_2 () {
-
this.eventManager.emit('event2', 23333)
-
}
-
-
}
起个名字
不同于单例模式,这个事件类可以实例化多份,我们可以搞个“起名字方法”,最后代码:
-
/** 事件数据接口 */
-
interface EventData {
-
callback: Function,
-
target: any
-
}
-
-
-
export class EventManager {
-
-
/** 事件存储 Map */
-
private eventsMap: Map<string, EventData> = new Map()
-
-
-
/** 该事件管理类的名字,方便区分 */
-
private name: string = undefined
-
-
-
/** 设置该管理类名称 */
-
public setEventManagerName (name: string) {
-
this.name = name
-
}
-
-
-
/** 获取名称,默认是 event-manager */
-
public getEventManagerName (): string {
-
return this.name === undefined ? 'event-manager' : this.name
-
}
-
-
-
/** 事件监听 */
-
public on (eventName: string, callback: Function, target: any) {
-
if (this.eventsMap.has(eventName)) {
-
console.warn(`${eventName} 事件已存在,覆盖`)
-
}
-
this.eventsMap.set(eventName, { callback, target })
-
}
-
-
-
/** 事件发送 */
-
public emit (eventName: string, data: any) {
-
if (!this.eventsMap.has(eventName)) {
-
console.warn(`${eventName} 事件不存在`)
-
return
-
}
-
const { callback, target } = this.eventsMap.get(eventName)
-
/** 执行回调 */
-
callback.call(target, data)
-
}
-
-
-
/** 取消事件 */
-
public off (eventName: string) {
-
if (!this.eventsMap.has(eventName)) {
-
console.warn(`${eventName} 事件不存在`)
-
return
-
}
-
this.eventsMap.delete(eventName)
-
}
-
-
-
}
结语
有 on 必有 off,不要让对象“假释放”哦,Map 中还有引用呢!
有没有带给你收获呢!O(∩_∩)O~~
微信公众号