vue探究:vue事件相关

vue $emit$on

vue 事件相关的函数挂载在vue的原型对象上面。分别为:vue

$on

vm.$on(event, callback)数组

const hookRE = /^hook:/
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
    const vm: Component = this
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        vm.$on(event[i], fn)
      }
    } else {
      (vm._events[event] || (vm._events[event] = [])).push(fn)
      // optimize hook:event cost by using a boolean flag marked at registration
      // instead of a hash lookup
      if (hookRE.test(event)) {
        vm._hasHookEvent = true
      }
    }
    return vm
}
复制代码

$on负责注册函数,事件以数组形式存贮在vm_event属性上。$on第一个参数容许传入字符串数组,数组的每一个成员对应的函数都是fn。 注意第一行定义了hookRE=/^hook:/这个正则,这样作的目的是:bash

vm.$on('hook:created', fn)
复制代码

当注册了一个hook:+声明周期的钩子函数以后,vue内部会在调用组件options提供的声明周期函数后还会调用一次用户经过$on注册的钩子函数。app

$off

vm.$off([event, callback])函数

Vue.prototype.$off = function (event, fn) {
    var this$1 = this;

    var vm = this;
    // 若是未传入任何参数,则删除全部事件
    if (!arguments.length) {
      vm._events = Object.create(null);
      return vm
    }
    // 数组形式循环删除数组的每一项事件
    // 对应$on以数据形式注册函数
    if (Array.isArray(event)) {
      for (var i = 0, l = event.length; i < l; i++) {
        this$1.$off(event[i], fn);
      }
      return vm
    }
    // 若是不存在该事件,则返回
    var cbs = vm._events[event];
    if (!cbs) {
      return vm
    }
    // 若是存在该event,但未传入钩子函数,则将事件置空。
    if (!fn) {
      vm._events[event] = null;
      return vm
    }
    if (fn) {
      // specific handler
      var cb;
      var i$1 = cbs.length;
      // 循环删除事件数组对应的每一项
      while (i$1--) {
        cb = cbs[i$1];
        // 注意这里的fn是引用传递,对应的内存函数是一个
        // 不然两个单独内存的函数没法进行比较
        if (cb === fn || cb.fn === fn) {
          cbs.splice(i$1, 1);
          break
        }
      }
    }
    return vm
};
复制代码

$once

vm.$once(event, fn)ui

Vue.prototype.$once = function (event, fn) {
    var vm = this;
    function on () {
      vm.$off(event, on);
      fn.apply(vm, arguments);
    }
    on.fn = fn;
    vm.$on(event, on);
    return vm
};
复制代码

这里的$once其实是将传入的event事件作了一个拦截改写,将fn钩子函数改写成on函数,on函数在调用时会先卸载改写的事件,并经过必包调用传入的原始钩子函数fn,注意这里将fn挂载在on删除上,是为了在调用off卸载事件时进行比较。this

$emit

vm.$emit(event, [...args])spa

Vue.prototype.$emit = function (event) {
    var vm = this;
    var cbs = vm._events[event];
    if (cbs) {
      cbs = cbs.length > 1 ? toArray(cbs) : cbs;
      // 获取除event以外的全部参数
      var args = toArray(arguments, 1);
      // 循环调用事件数组的每一项
      for (var i = 0, l = cbs.length; i < l; i++) {
        try {
          // 给事件this绑定为vm
          cbs[i].apply(vm, args);
        } catch (e) {
          handleError(e, vm, ("event handler for \"" + event + "\""));
        }
      }
    }
    return vm
  };
}
复制代码

$emit做用是充当发布者的角色触发事件,而全部的事件会以数组形式存储在vm的_event中。prototype

callhook

callhook不算是vue event事件相关的成员函数,但vue的声明周期函数都是经过callhook函数调用,也算是充当发布者的角色。code

function callHook (vm, hook) {
  ...
  var handlers = vm.$options[hook];
  var info = hook + " hook";
  if (handlers) {
    for (var i = 0, j = handlers.length; i < j; i++) {
      invokeWithErrorHandling(handlers[i], vm, null, vm, info);
    }
  }
  if (vm._hasHookEvent) {
    vm.$emit('hook:' + hook);
  }
  ... 
}
复制代码

首先,callHook会先调用组件options上挂载的声明周期函数。在介绍$on方法时,发现只要以hook:注册的声明周期钩子函数,会将_hasHookEvent变为true,这时,再经过callhook调用options的声明周期钩子函数时,还会在调用以hook:事件挂载在vm._event上的钩子函数。

所以,当咱们想监听声明周期函数是否调用时,能够经过vm.$on('hook:created', cb)来实现。

文章内容若有错误,敬请谅解,但愿能够不吝赐教

转载请注明出处,感谢

相关文章
相关标签/搜索