记录自己手写的发布订阅事件(EventEmitter)

197 阅读2分钟

前言

发布订阅事件大家一定不陌生了,通过监听某个事件然后执行相应的操作,在Vue中,eventBus、emit、$on就是利用订阅事件来做的。说实在,个人体验最深的就是在Vue使用树形组件递归树形数据最常用了,在递归组件中使用传统的props是无法做到向父组件传递数据的,此时,订阅事件就发挥了他的作用。

实现

订阅事件是如此的强大,自己手撸一个吧。

    class EventEmitter{
        constructor(){
            // 保留传进来的自定义事件回调函数
            this.events={};
        }
        // 发送事件
        emit(eventName,payload){
            //获取自定义事件的回调事件队列
            let callbackQuene=this.events[eventName];
            // console.log(callbackQuene)
            // 执行回调事件队列
            Array.isArray(callbackQuene)&&callbackQuene.forEach(callback => {
                callback.apply(this,[payload])
            });
        }
        // 监听事件
        on(eventName,callback){
            // 判断自定义事件是否已注册
            if(!this.events[eventName]){
               this.events[eventName]=[];
            };
            this.events[eventName].push(callback);
        }
        // 卸载事件
        off(eventName,callback){
            // 没传参数,默认取消所有监听事件
            if(typeof eventName==="undefined"){
                delete this.events
            }
            // 取消指定事件回调
            else if(typeof eventName==="string"){
                // 判断事件是否已注册
                if(this.events[eventName]&&Array.isArray(this.events[eventName])){
                    // 判断callback是否为函数
                    if(typeof callback==="function"){
                        // 过滤指定函数
                           this.events[eventName]=this.events[eventName].filter(cb=>cb!==callback);
                    }else{
                        this.events[eventName]=[];
                    }
                }    
            }
        }
        // 监听一次自动后自动卸载事件
        once(eventName,callback){
            const onceCallback=(payload)=>{
                callback.apply(this,[payload])
                this.off(eventName,onceCallback)
            }
            this.on(eventName,onceCallback);
        }
    }
    //实例化
    const myEventEmitter=new EventEmitter();
    //注册并监听事件
    myEventEmitter.on('emit',(data)=>{
        console.log(data)
    });
    setTimeout(()=>{
        myEventEmitter.emit('emit','我是emit事件'); //3秒后输出
    },3000);
    
    //不传参数,取消所有事件监听
    myEventEmitter.off();
    //传参数与不传回调函数,取消指定事件的所有回调函数
    myEventEmitter.off('emit');
    //传参数与取消指定回调函数
    myEventEmitter.off('emit',(data)=>{
        console.log(data)
    });
    //只执行一次回调函数
    myEventEmitter.once('once',(data)=>{
        console.log('once')
    })
    setTimeout(()=>{
        myEventEmitter.emit('once',{});//3秒后输出once
    },3000);
    setTimeout(()=>{
        myEventEmitter.emit('once');//不再输出once
        console.log(66)
    },5000)

结语

手动实现还是挺简单的,各位也可以自己手撸一个,加深理解,毕竟好记性不如烂笔头。哎呀,头发又掉了好几根......