文章

手写一个事件调度器以在小程序中实现跨页面通信
2018/11/07

开头

最近在接触微信小程序,学习过程中发现原生框架不自带跨页面通信 API,这样如果想实现由一个 page 的行为变动引起另一个 page 状态的改变的话,除了用传 this 参数或者通过 getCurrentPages() 获取当前页面实例然后用 this.setData() 触发视图更新,也没有其他更好的办法了,然而上面这两个方法非常不利于后期维护。于是手写一个兼具 EventListening, EventPublishing, EventCanceling 功能的事件调度器放在小程序的 App.js 全局环境中让任何一个页面可以使用这三个接口去通信,这可以降低耦合度,便于维护与升级。

那就来看看代码吧

class Event {
    constructor(){
        // 初始化事件调度中心
        this._eventCenter = {}
    }
    /**
     *
     * @param {String} eventName 
     * @param {Function} callback 
     */
    on(eventName, callback, context){
        // 获得该事件的 callback 数组,如果不存在自动创建并向该事件分类 push callbacks 与 context
        (this._eventCenter[eventName] = this._eventCenter[eventName] || []).push({callback:callback,context:context})
    }
    /**
     * 
     * @param {String} eventName 
     * @param {*} prop 
     */
    emit(eventName, ...props){
        // 对该事件类的 callback 执行并带入参数
        (this._eventCenter[eventName] = this._eventCenter[eventName] || []).forEach((item)=>{
            item.callback.apply(item.context, props)
        })
    }
    /**
     * 
     * @param {String} eventName 
     * @param {Function} callback 
     */
    remove(eventName, ...callbackTrash){
        // 如果不传任何参数重置整个事件集则初始化整个 eventCenter
        if(arguments.length === 0){
            this._eventCenter = {}
            return
        }
        // 如果不传入特定 callback 则删除整个 event 类
        if(arguments.length === 1){
            delete this._eventCenter[eventName]
            return
        }
        // 如果传入一个不存在的事件名则提前结束
        if(!this._eventCenter[eventName]) return
        // 删除指定的 callback
        let callbacksInThisEvent = this._eventCenter[eventName];
        for (item1 of callbackTrash){
            for (let i in callbacksInThisEvent){
                if (item1 === callbacksInThisEvent[i].callback) {
                    callbacksInThisEvent.splice(i, 1)
                    break
                }
            }
        }
    }
}

好奇心阅读

如何在微信小程序里面实现跨页面通信?-- GitHub @dannnney