优雅的模块化-事件监听-On与Emit的实现

摘要

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

微信公众号

发布了130 篇原创文章 · 获赞 147 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/kuokuo666/article/details/104998542
今日推荐