摘要
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~~