摘要

CocosCreator 有着内置的事件系统,我们用起来也很是方便。那么我们自己如何简单的实现一个 EventManager 呢?KUOKUO 通过一个小例子带你学习。

正文

使用版本

CocosCreator 版本 2.2.2

明确目标

我们要做一个事件管理模块,实现事件的监听方法 on,取消方法 off,事件发送 emit。

优雅的模块化-事件监听-On与Emit的实现_数据接口

事件数据类型

首先,我们要想好事件用什么存储。选择用 Map,则需要一个事件名称,类型 string,还有就是一个对象,存放 callback 以及调用者 target。让我们规定一下类型:

  1. /** 事件数据接口 */

  2. interface EventData {

  3. callback: Function,

  4. target: any

  5. }

存储Map

让我们写出类的名称:

  1. export class EventManager {

  2. }

声明其私有的 Map:

  1. private eventsMap: Map<string, EventData> = new Map()

存入事件

on 的实现就是将传入的参数进行存储,如果这个事件已经有了,就覆盖掉:

  1. public on (eventName: string, callback: Function, target: any) {

  2. if (this.eventsMap.has(eventName)) {

  3. console.warn(`${eventName} 事件已存在,覆盖`)

  4. }

  5. this.eventsMap.set(eventName, { callback, target })

  6. }

与之对应的取消监听,就是将事件从 Map 中删除:

  1. public off (eventName: string) {

  2. if (!this.eventsMap.has(eventName)) {

  3. console.warn(`${eventName} 事件不存在`)

  4. return

  5. }

  6. this.eventsMap.delete(eventName)

  7. }

事件的发送

最重要的一步是事件的发送,我们首先要取到 Map 中对应的事件,然后利用 call 或者 apply 使其在 target 的作用域下被调用(使用箭头函数会使得这个 target 无效,会指向声明时的 this)。

  1. public emit (eventName: string, data: any) {

  2. if (!this.eventsMap.has(eventName)) {

  3. console.warn(`${eventName} 事件不存在`)

  4. return

  5. }

  6. const { callback, target } = this.eventsMap.get(eventName)

  7. /** 执行回调 */

  8. callback.call(target, data)

  9. }

data 参数可以拓展多个,但是实际上用对象包住,一个也是可以的,比如测试代码:

  1. this.eventManager.emit('event1', { data1: 'kuokuo', data2: [6, 6, 6] })

实际测试

写一个测试脚本,里面做两个事件监听,新建两个按钮,分别绑定到脚本中的 onClick 方法:

  1. import { EventManager } from "./EventManager"

  2. const {ccclass, property} = cc._decorator

  3.  

  4. @ccclass

  5. export default class Test extends cc.Component {

  6.  

  7. eventManager: EventManager = new EventManager()

  8.  

  9. onLoad () {

  10. // 监听事件1

  11. this.eventManager.on('event1', (data) => {

  12. console.log('事件1触发,数据为:')

  13. console.log(data)

  14. }, this)

  15. // 监听事件2

  16. this.eventManager.on('event2', (data) => {

  17. console.log('事件2触发,数据为:')

  18. console.log(data)

  19. }, this)

  20. }

  21.  

  22. onClick_1 () {

  23. this.eventManager.emit('event1', { data1: 'kuokuo', data2: [6, 6, 6] })

  24. }

  25.  

  26. onClick_2 () {

  27. this.eventManager.emit('event2', 23333)

  28. }

  29.  

  30. }

优雅的模块化-事件监听-On与Emit的实现_管理类_02

起个名字

不同于单例模式,这个事件类可以实例化多份,我们可以搞个“起名字方法”,最后代码:

  1. /** 事件数据接口 */

  2. interface EventData {

  3. callback: Function,

  4. target: any

  5. }

  6.  

  7.  

  8. export class EventManager {

  9.  

  10. /** 事件存储 Map */

  11. private eventsMap: Map<string, EventData> = new Map()

  12.  

  13.  

  14. /** 该事件管理类的名字,方便区分 */

  15. private name: string = undefined

  16.  

  17.  

  18. /** 设置该管理类名称 */

  19. public setEventManagerName (name: string) {

  20. this.name = name

  21. }

  22.  

  23.  

  24. /** 获取名称,默认是 event-manager */

  25. public getEventManagerName (): string {

  26. return this.name === undefined ? 'event-manager' : this.name

  27. }

  28.  

  29.  

  30. /** 事件监听 */

  31. public on (eventName: string, callback: Function, target: any) {

  32. if (this.eventsMap.has(eventName)) {

  33. console.warn(`${eventName} 事件已存在,覆盖`)

  34. }

  35. this.eventsMap.set(eventName, { callback, target })

  36. }

  37.  

  38.  

  39. /** 事件发送 */

  40. public emit (eventName: string, data: any) {

  41. if (!this.eventsMap.has(eventName)) {

  42. console.warn(`${eventName} 事件不存在`)

  43. return

  44. }

  45. const { callback, target } = this.eventsMap.get(eventName)

  46. /** 执行回调 */

  47. callback.call(target, data)

  48. }

  49.  

  50.  

  51. /** 取消事件 */

  52. public off (eventName: string) {

  53. if (!this.eventsMap.has(eventName)) {

  54. console.warn(`${eventName} 事件不存在`)

  55. return

  56. }

  57. this.eventsMap.delete(eventName)

  58. }

  59.  

  60.  

  61. }

结语

有 on 必有 off,不要让对象“假释放”哦,Map 中还有引用呢!

有没有带给你收获呢!O(∩_∩)O~~

微信公众号

优雅的模块化-事件监听-On与Emit的实现_数据接口_03