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)來實現。

文章內容若有錯誤,敬請諒解,但願能夠不吝賜教

轉載請註明出處,感謝

相關文章
相關標籤/搜索