Vue source code analysis - custom event handlers

There are four events Vue.js API can be used to handle custom events, were $ on, $ once, $ off, $ emit.

initialization

When introducing Vue.js Vue will bind some of the methods and properties of the Function prototype. Source codevue-2.6.11/src/core/instance/index.js

function Vue (options) {
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

EventsMixin method which bound the $ on, $ once, $ off, $ emit four methods to the Vue Function prototype. Source codevue-2.6.11/src/core/instance/index.js

export function eventsMixin (Vue) {
   Vue.prototype.$on = function (event, fn) {}
   Vue.prototype.$once = function (event, fn) {}
   Vue.prototype.$off = function (event, fn) {}
   Vue.prototype.$emit = function (event) {}
}

Call initEvents method initMixin method to initialize the event object. Source codevue-2.6.11/src/core/instance/index.js

export function initEvents (vm: Component) {
  vm._events = Object.create(null)
}

$on

$ on the method used to listen in on a vm instance a custom event that triggered the available $ emit.
Usage
The first argument is a string or array, and the second is a callback function.

this.$on('event',()=>{})
this.$on(['event1','event2'],()=>{})

Source

  Vue.prototype.$on = function (event: string | Array<string>, fn: Function){
    const vm = 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)
    }
    return vm
  }

Source means that when using the $ on listening in on an instance of a custom event, will perform the $ on method on the prototype. Event first determines whether the first parameter is an array, if it is a flat array processing, until it is not an array. If not an array of objects _event first determine the event there is no key attribute for the event, if not create an empty array of a key for the event gave _event on the object, and then add the callback function fn to the array. If there is an array of key event properties, add the fn directly to the array. The last event object is like this:

_event:{
   event: [func1, func2, func3]
}

$once

$ once a listener can only be triggered once the event is automatically removed after the trigger event.
Usage
The first parameter is a string, the second is a callback function.

this.$once('event',()=>{})

Source

  Vue.prototype.$once = function (event: string, fn: Function){
    const vm = this
    function on () {
      vm.$off(event, on)
      fn.apply(vm, arguments)
    }
    on.fn = fn
    vm.$on(event, on)
    return vm
  }

Source means that when a listener can only be triggered once the custom event will execute $ once method on an instance. First on the definition of a function. Then bound to the callback function fn on the function (the reason will be explained in explaining the $ off). The last method call on a $ monitor events on the second parameter becomes the function. on function first remove the custom event and then execute the callback function. In fact, $ once fn callback function is to do a rewrite, in order for the callback function fn executed only once removed.

$off

$ off is used to remove the custom event.
Usage
The first argument is a string or array, and the second is a callback function.

  • Case 1: If no parameters, then remove all the event listeners;
  • Case 2: If only event, then remove all the event listeners;
  • Case 3: If both events and callbacks, only remove this callback listener.
this.$off()
this.$off('event')
this.$off('event',callback)

Source

  Vue.prototype.$off = function (event?: string | Array<string>, fn?: Function){
    const vm = this
    // all
    if (!arguments.length) {
      vm._events = Object.create(null)
      return vm
    }
    // array of events
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        vm.$off(event[i], fn)
      }
      return vm
    }
    // specific event
    const cbs = vm._events[event]
    if (!cbs) {
      return vm
    }
    if (!fn) {
      vm._events[event] = null
      return vm
    }
    // specific handler
    let cb
    let i = cbs.length
    while (i--) {
      cb = cbs[i]
      if (cb === fn || cb.fn === fn) {
        cbs.splice(i, 1)
        break
      }
    }
    return vm
  }

Source means that when you remove a custom event on the instance, will perform the $ off method.

  1. If no arguments directly to the event object _event become hollow and return. 1 corresponds to the case.

  2. Otherwise the event is not a judged event array, if the array is on a flat processing, not until the array. Then get to the event object _event the key to the value of the event. If there is no return. Otherwise, continue to determine if there is no callback function fn will be the property value of the event called the event becomes null and then return. 2 corresponds to the situation.

  3. If the event is present, and the callback function is also present, the array properties of circulating event corresponding to the event object. Until you find and callback functions fn same references in the array. There are two cases, one is the direct use $ monitor events on the other is to use $ once listening event, use the $ once listening to rewrite the events leading event because the object _event corresponding value added is on key function. $ Off execution words will not be found in an array corresponding to get a callback function. Therefore, to $ once the binding on the original function callback fn. When you find the corresponding event and delete array exit the loop. 3 corresponds to the situation.

$emit

$ emit used to trigger specified custom events.
Usage
The first parameter is the event name, type a string, additional parameters are passed to the listener callback.

this.$emit('event')
this.$emit('event','n1','n2')

Source

  Vue.prototype.$emit = function (event: string){
    const vm = this
    let cbs = vm._events[event]
    if (cbs) {
      cbs = cbs.length > 1 ? toArray(cbs) : cbs
      const args = toArray(arguments, 1)
      const info = `event handler for "${event}"`
      for (let i = 0, l = cbs.length; i < l; i++) {
      	//args ? handler.apply(context, args) : handler.call(context)
        invokeWithErrorHandling(cbs[i], vm, args, vm, info)
      }
    }
    return vm
  }

Source means that when trigger a custom event on the instance, will execute $ emit method. First get events corresponding to the value of the event object _event in. If there is to get all parameters except the first argument. Then converted to an array. The last event loop execution method array. And the parameters corresponding to the array have passed the callback function.

to sum up

These are the principles of a custom event processing. There are three questions after reading the source code.

  1. Use $ once, why the first argument is not an array, the official website of documentation and source code in the first parameter type only strings, did not write the array. I passed the test array is no problem ah.
  2. Why use $ off after removing an event only once to find a break in the final while loop, if there is the same array inside of it. To address this problem, I used to listen $ on two of the same events and the same callback function. Then use the $ off to remove the same event and the same callback function, only to remove one, there is a presence. I do not know why.
  3. Why in the $ emit the execution cbs = cbs.length > 1 ? toArray(cbs) : cbssentence. toArray in the source code means that this class will be converted to an array of arrays. In this look at cbs must be an array do not need to turn ah. I do not know why consideration.
Published 67 original articles · won praise 16 · views 20000 +

Guess you like

Origin blog.csdn.net/qwe435541908/article/details/103956787