1. 程式人生 > >Vue原始碼解析(三)

Vue原始碼解析(三)

接下來呼叫eventsMixin方法,看名稱就知道是關於事件相關的,主要是在Vue的原型上加入$on,$once,$off,$emit方法。

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

    var vm = this;
    if (Array.isArray(event)) {
      for (var i = 0, l = event.length; i < l; i++) {
        this$1.$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方法為監聽自定義事件,如果event為陣列,則遍歷event陣列進行監聽。如果為字串則放入vm._events陣列中。這塊還進行了一個事件是否為Hook的正則判斷,暫未搞清楚具體作用。

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

    var vm = this;
    // all
    if (!arguments.length) {
      vm._events = Object.create(null);
      return vm
    }
    // array of events
    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 } // specific event var cbs = vm._events[event]; if (!cbs) { return vm } if (arguments.length === 1) { vm._events[event] = null; return vm } // specific handler var cb; var i = cbs.length; while (i--) { cb = cbs[i]; if (cb === fn || cb.fn === fn) { cbs.splice(i, 1); break } } return vm };

$off方法為解除已繫結的事件,如果off方法不傳任何引數,刪除所有繫結事件。如果event為陣列,則迴圈解除陣列內的事件。如果為字串,事件陣列不存在則直接返回;如果不需要回調,則將相關事件陣列設為null。如果該事件陣列有存在,則遍歷事件陣列,並從陣列中刪除符合條件的事件。

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方法為繫結僅響應一次事件,響應結束後立即解除繫結。主要是呼叫了$on方法,同時回撥時呼叫$off方法解除該事件,並再解除事件後進行回撥。

Vue.prototype.$emit = function (event) {
    var vm = this;
    {
      var lowerCaseEvent = event.toLowerCase();
      if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
        tip(
          "Event \"" + lowerCaseEvent + "\" is emitted in component " +
          (formatComponentName(vm)) + " but the handler is registered for \"" + event + "\". " +
          "Note that HTML attributes are case-insensitive and you cannot use " +
          "v-on to listen to camelCase events when using in-DOM templates. " +
          "You should probably use \"" + (hyphenate(event)) + "\" instead of \"" + event + "\"."
        );
      }
    }
    var cbs = vm._events[event];
    if (cbs) {
      cbs = cbs.length > 1 ? toArray(cbs) : cbs;
      var args = toArray(arguments, 1);
      for (var i = 0, l = cbs.length; i < l; i++) {
        cbs[i].apply(vm, args);
      }
    }
    return vm
  };

$emit方法為事件下發的方法,首先進行了一個大小寫的判斷,如果註冊事件和下發事件的大小寫不一致,則發出警告。如果該事件陣列存在,則遍歷事件陣列進行註冊回撥,同時使用apply方法傳遞呼叫時引數。