这个API根据参数的不同实现了以下几个功能:

  • 取消监听所有事件
  • 取消监听某一个事件
  • 移除某个事件的某个回调
  • 移除多个事件的某个回调

既然已经知道了这个自定义事件的数据组织形式,实现这些功能并不复杂:

  • 取消监听所有事件,把_event清空
  • 取消监听某个事件,把_event[eventName]清空
  • 移除某个事件的某个回调,遍历一遍找到回调然后从数组中移除
  • 移除多个事件的某个回调,利用第三个功能即可
Vue.prototype.$off = function (event, fn) {
    var this$1 = this;
    var vm = this;
    //取消监听所有事件
    if (!arguments.length) {
        vm._events = Object.create(null);
        return vm
    }

    // 取消监听多个事件的特定回调
    if (Array.isArray(event)) {
        for (var i$1 = 0, l = event.length; i$1 < l; i$1++) {
            this$1.$off(event[i$1], fn);
        }
        return vm
    }
    var cbs = vm._events[event];
    if (!cbs) {
        return vm
    }

    // 取消监听某个事件
    if (arguments.length === 1) {
        vm._events[event] = null;
        return vm
    }
    var cb;
    var i = cbs.length;
    // 取消监听某个事件的特定回调
    while (i--) {
        cb = cbs[i];
        if (cb === fn || cb.fn === fn) {
            cbs.splice(i, 1);
            break
        }
    }
    return vm
};

根据上面所拆解的功能,这段代码就很好理解了,我也添加了必要的注释。

还有几点小细节:

作者在这里实现了链式调用,不过这也是标配了吧。

实现第三个功能时的遍历,作者采用了while循环逆向查找,这么做是为了减少操作优化性能,具体原理请看《高性能JavaScript》。

判断是否是特定回调时,使用cb === fn || cb.fn === fn,你可能会奇怪为什么有cb.fn === fn这个判断,看了下面的$once方法的实现你就明白了。

results matching ""

    No results matching ""