vue 源码 event

2021-01-11  本文已影响0人  Wendy81

在moduel包中 vue/dist/vue.runtime.esm.js

了解vue上的

$on, $emit,  $once,  $off
//刚开始初执行
eventsMixin(Vue);
......
//这里我们查看对应的函数部分
function eventsMixin (Vue) {
  var hookRE = /^hook:/;
  Vue.prototype.$on = function (event, fn) {
    var vm = this;
    if (Array.isArray(event)) {
      for (var 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
  };

  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
  };

  Vue.prototype.$off = function (event, fn) {
    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++) {
        vm.$off(event[i$1], fn);
      }
      return vm
    }
    // specific event
    var cbs = vm._events[event];
    if (!cbs) {
      return vm
    }
    if (!fn) {
      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
  };

  Vue.prototype.$emit = function (event) {
    var vm = this;
    if (process.env.NODE_ENV !== 'production') {
      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);
      var info = "event handler for \"" + event + "\"";
      for (var i = 0, l = cbs.length; i < l; i++) {
        invokeWithErrorHandling(cbs[i], vm, args, vm, info);
      }
    }
    return vm
  };
}

下面面这样写实际上已经执行了Vue.prototype.$on

<div id ="app">
    <HelloWorld @showCityName="clickHanlder" msg="Welcome to Your Vue.js App"/>
</div>

export default {
.....
   methods: {
    clickHanlder(data){
     //这里的data就是下面子组件用$emit调用这个event时传过的参数 {a:10}
      alert(data.a)
    }
   }
}
Vue.prototype.$on = function (event, fn) {
    ......
    console.log(event)
    // 这里的event 就是showCityName
    .....
}

然后在子组件即HelloWorld中我们可以用Vue.prototype.emit来触发上面Vue.prototype.on定义的事件showCityName

<template>
  <div id="hello" class="hello">
    <button @click="clickHanlder">click</button>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  methods: {
    clickHanlder(){
      //这里我们可以用$emit调用父组件的 showCityName事件,并传参过去
      this.$emit('showCityName',{a:10})
    }
  }
}
</script>

从上面的事件中我们可以了解以:

1.vue中用on定义的事件,可以在子组件中用vue中的emit直接调用并传参给$on定义的事件

2.$once : 只添加一次事件

3. $off :

. vue把事件添加到一个数组队列里面,通过删除该数组事件队列,而达到解绑事件
.移除自定义事件监听器。
.如果没有提供参数,则移除所有的事件监听器;
.如果只提供了事件,则移除该事件所有的监听器;
上一篇下一篇

猜你喜欢

热点阅读