js

vue.js的事件机制实现

Posted by wml on March 26, 2019

vue事件机制

vue官方Api上提供了四个事件,$on, $once, $off, $emit, 这几个事件都是基于订阅观察者模式实现的,在vm上创建一个event对象存放时间,on方法将事件添加到事件中心,emit将对应的事件发布,off移除对应事件,once监听自定义时间,但只触发一次。

实现原理

实现一个简易的方法,拥有以上几个事件。

class Vm {
    _events = {}  // 定义一个空的事件

    on(event, fn) {  // event: string | array
        if(Array.isArray(event)) { //多个事件
            event.forEach(item => this.on(item, fn))
        }else {
            (this._events[event] || (this._events[event] = [])).push(fn);  //将事件推送进事件中心(||优先级比=高)
        }
    }

    emit(event) {
        const fns = this._events[event];
        const args = Array.from(arguments).slice(1);
        if(fns) {
            fns.forEach(fn => fn.apply(this, args)) // 遍历执行
        }
    }

    once(event, fn) {
        function oneTime() {  
            this.off(event, oneTime);  // 第一次执行时将该事件销毁
            fn.apply(this, arguments)  // 执行fn方法
        }
        this.on(event, oneTime);
    }

    off(event, fn) {
        if(!arguments.length)  {  // 为指定事件名称,清空所有事件
           this._events = Object.creact(null);
           return;
        }

        if(Array.isArray(event)) {  // 多个事件递归注销事件
           event.forEach(evt => this.off(evt, fn))
        }

        const fns = this._events[event];
        if(!fns) return;  // 如果不存在该事件直接返回

        if(!fn) { // 未指定事件的对应方法,则注销该事件下的所有方法
            this._events[event] = null;  
            return;
        }

        const idx = fns.indexOf(fn);
        if(idx > -1) {
          fns.splice(i, 1);
        }

        // for(var i = 0; i < fns.length; i++) {  // 遍历event下的方法
        //     if(fns[i] === fn) {
        //         fns.splice(i, 1);
        //         break;
        //     }
        // }
    }
}

on方法测试

let vm = new Vm();
vm.on(['a', 'b'], ()=>console.log(1));
vm.on('a', ()=>console.log(2));

1

emit方法测试

vm.emit('a');  //1,2
vm.emit('b'); // 1

off方法测试

vm.off('b')

2

once方法测试

vm.once('c', ()=>console.log('cccc'))
vm.emit('c'); //ccc

3

4