Writing in the front

Because of the vue. js is very interested in, and the usual work of the technology stack vue. js, these months spent some time to study the vue. js source code, and do a summary and output. Original address of the article: github.com/answershuto… . In the process of learning, I added Chinese annotations for Vue github.com/answershuto… , hope can be helpful to other want to learn Vue source partners. There may be some misunderstanding, welcome to point out, learn together, make progress together.

Vue event apis

As we all know, vue.js provides us with four event apis: $ON, $once, $off, and $emit.

Initialization event

Initializing events Creates a _events object on the VM to hold events. The contents of _events are as follows:

{
    eventName: [func1, func2, func3]
}Copy the code

Store event names and corresponding execution methods.

/* Initialize the event */
export function initEvents (vm: Component) {
  /* Create a _events object on the VM to hold events. * /
  vm._events = Object.create(null)
  /* The bool flag indicates the presence or absence of hooks, rather than the need to hash the presence or absence of hooks, which can reduce unnecessary overhead and optimize performance. * /
  vm._hasHookEvent = false
  // init parent attached events
  /* Initializes the parent attach event */
  const listeners = vm.$options._parentListeners
  if (listeners) {
    updateComponentListeners(vm, listeners)
  }
}Copy the code

$on

The $ON method is used to listen for a custom event on the VM instance that can be fired by $emit.

  Vue.prototype.$on = function (event: string | Array<string>, fn: Function) :Component {
    const vm: Component = this

    /* If it is an array, recurse $on to bind method */ for each member
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.$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
      /* Bool is a flag bit to indicate the presence of a hook, rather than the need to hash the table to find the presence of a hook. * /
      if (hookRE.test(event)) {
        vm._hasHookEvent = true}}return vm
  }Copy the code

$once

$once listens for an event that can only be triggered once and automatically removes the event after it is triggered.

  Vue.prototype.$once = function (event: string, fn: Function) :Component {
    const vm: Component = this
    function on () {
      /* Destroy the event on the first execution */
      vm.$off(event, on)
      /* The registration method */
      fn.apply(vm, arguments)
    }
    on.fn = fn
    vm.$on(event, on)
    return vm
  }Copy the code

$off

$off is used to remove custom events

Vue.prototype.$off = function (event? : string | Array
       
        , fn? : Function
       ) :Component {
    const vm: Component = this
    // all
    /* If no parameter is passed, log out all events */
    if (!arguments.length) {
      vm._events = Object.create(null)
      return vm
    }
    // array of events
    /* Recursively cancel the event if the event is an array */
    if (Array.isArray(event)) {
      for (let i = 0, l = event.length; i < l; i++) {
        this.$off(event[i], fn)
      }
      return vm
    }
    // specific event
    const cbs = vm._events[event]
    /*Github:https://github.com/answershuto*/
    /* If the event does not exist, return */
    if(! cbs) {return vm
    }
    /* If only the event argument is passed, log out all methods */
    if (arguments.length === 1) {
      vm._events[event] = null
      return vm
    }
    // specific handler
    /* traverse for the corresponding method and delete */
    let cb
    let i = cbs.length
    while (i--) {
      cb = cbs[i]
      if (cb === fn || cb.fn === fn) {
        cbs.splice(i, 1)
        break}}return vm
  }Copy the code

$emit

$emit is used to trigger the specified custom event.

Vue.prototype.$emit = function (event: string) :Component {
    const vm: Component = this
    if(process.env.NODE_ENV ! = ='production') {
      const 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}". `)}}let cbs = vm._events[event]
    if (cbs) {
      /* Convert an array-like object to an array */
      cbs = cbs.length > 1 ? toArray(cbs) : cbs
      const args = toArray(arguments.1)
      /* Execute */
      for (let i = 0, l = cbs.length; i < l; i++) {
        cbs[i].apply(vm, args)
      }
    }
    return vm
  }Copy the code

about

Author: Ran Mo

Email: [email protected] or [email protected]

Github: github.com/answershuto

Blog: answershuto. Making. IO /

Zhihu homepage: www.zhihu.com/people/cao-…

Zhihu column: zhuanlan.zhihu.com/ranmo

The Denver nuggets: juejin. Cn/user / 289926…

OsChina:my.oschina.net/u/3161824/b…

Please indicate the source of reprint, thank you.

Welcome to follow my public number