手写 EventBus(Vue)

Vue 中事件相关的方法 vm.$on、vm.$off、vm.$once、vm.$emit,通过eventsMinxin方法挂在 Vue的原型上。

定义一个事件总线对象 events 管理所有事件:
    每次执行$on的时候,都会在 events 中对应事件的回调函数列表中添加一项;
    每次执行$emit的时候,会执行 events 中对应事件的所有函数。

/*
    this.events = {
        event1:[callback1,callback2,…………],
        event2:[callback1,callback2,…………],...
    }
*/
class EventBus {
    constructor() {
        // 事件总线对象
        this.events = {};
    }

    // 监听 发布,  event事件可以为数组和字符串,fn为事件触发时的回调函数
    $on(event, fn) {
        if (Array.isArray(event)) {
            for (let i = 0; i < event.length; i++) {
                // 监听数组中的每一个事件
                this.$on(event[i], fn)
            }
        } else {
            // 该事件的事件队列 如果存在就直接push进去fn,如果不存在就先创建为空数组
            (this.events[event] || (this.events[event] = [])).push(fn);
        }
    }

    // 触发事件event,...args为调用时的传参
    $emit(event, ...args) {
        const cbs = this.events[event];
        cbs.forEach(fn => {
            try {
                fn(...args);
            } catch (e) {
                new Error('error')
            }
        });
    }

    // 清除某个event事件的fn
    $off(event, fn) {
        // 不传具体参数event时,就清空所有事件
        if (!arguments.length) this.events = {};

        if (Array.isArray(event)) {
            for (let i = 0; i < event.length; i++) {
                // 清除数组中的每一个事件
                this.$off(event[i], fn)
            }
            return;
        }

        const cbs = this.events[event];
        if (!cbs) return;
        // 如果不传参数fn,就清除该事件的所有回调函数
        if (arguments.length == 1) this.events[event] = null;
        else {
            // 该事件的事件队列
            let n = cbs.length;
            while (n--) {
                if (cbs[n] === fn || cbs[n].fn === fn) {
                    cbs.splice(n, 1);
                    break;
                }
            }
        }
    }

    // 注册监听事件和处理函数,触发一次后销毁,  event为字符串
    $once(event, fn) {
        const self = this;
        // 给fn做一层处理,使得触发时先清除
        function handler() {
            self.$off(event, handler);
            fn.apply(self, arguments);  //emit触发时会传入参数args
        }
        handler.fn = fn;  //off清除时的判断依据

        this.$on(event, handler);
    }
}

const eb = new EventBus();
eb.$on('say', function (msg) {
    console.log(msg);
});
eb.$emit('say', 'Hello world');

你可能感兴趣的:(#,JS手写,javascript,vue.js)