Let’s start with an interview question.

The interviewer asked, “What are the common ways components communicate in Vue?” My answer:

Props 2. Customize events 3. Eventbus 4. \$parent, \$children, \$root, \$refs, provide/inject 6. There are also some non-props features \$attrs, \$ListenersCopy the code

“Can you explain how each of them works?” the interviewer asked. I: [a face meng force]😳

Here we take a look at their secrets! For other attribute principles, go to Vue component communication Principle Analysis (2) Global state management Vuex and Vue component communication principle Analysis (3) Provide/Inject principle analysis

props

Problem solved: Parent passes value to child

// child
props: {
  msg: {
    type: String.default: ' '}}// parent
<child msg="This is the parameter passed to the child component."></child>
Copy the code

Custom events

Problem solved: child passes value to parent

// child
this.$emit('add'.'This is the argument that the child passes to the parent')

// parent
// parantAdd is an event defined in the parent component. The event takes the value passed by the child component to the parent
<child @add="parentAdd($event)"></child>
Copy the code

EventBus

Problem solved: passing values between any two components

// This is how we usually do it
// main.js 
Vue.prototype.$bus = new Vue()

// child1
this.$bus.$on('foo', handle)

// child2
this.$bus.$meit('foo')
Copy the code

So how does communication between components work? How are on and ON and ON and EMIT implemented? Let’s go! Let’s go!

$on = $on
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)
    }
    return vm
  }

// $emit implementation logic
Vue.prototype.$emit = function (event: string) :Component {
    const vm: Component = 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++) {
        invokeWithErrorHandling(cbs[i], vm, args, vm, info)
      }
    }
    return vm
  }

// invokeWithErrorHandling implements the logic
export function invokeWithErrorHandling (
  handler: Function,
  context: any,
  args: null | any[],
  vm: any,
  info: string
) {
  let res
  try {
    res = args ? handler.apply(context, args) : handler.call(context)
  } catch (e) {
    handleError(e, vm, info)
  }
  return res
}
Copy the code

Above is the implementation we found in the source code, which has some debugging code I have removed, so that you can grasp the main point! Let’s analyze them one by one

  1. First of all, we all know that vUE data is dependent on the “observation-subscribe” mode. On, ON, ON, emit are no exception.
  2. $on is used to collect all event dependencies, which will pass in parameterseventandfnStored as key and valuevm._eventsIn this set of events, it looks like thisvm._events[event]=[fn];
  3. While $emit is used to trigger events, it will follow the incomingeventinvm_eventsFind the corresponding event and execute itinvokeWithErrorHandling(cbs[i], vm, args, vm, info)
  4. Finally we look at the invokeWithErrorHandling method and see that it is throughhandler.apply(context, args)andhandler.call(context)Execute the corresponding method in the form of

Isn’t it easy? [laughing]

Now that we know how to implement it, we can implement a custom Bus, see the code

// Bus: event dispatch, listening, and callback
class Bus {
  constructor() {
    this.callbacks = {}
  }

  // Collect the listening callback function
  $on(name, fn) {
    this.callbacks[name] = this.callbacks[name] || []
    this.callbacks[name].push(fn)
  }

  // Execute the listening callback function
  $emit(name, args) {
    if (this.callbacks[name]) {
      this.callbacks[name].forEach(cb= > cb(args))
    }
  }
}

// Use this in main.js
Vue.prototype.$bus = new Bus()

Copy the code

At this point, the principle of the bus analysis is here.

Links to all articles

Vue component communication principle analysis (a) the cornerstone of the event bus
o n and On and
emit

Analysis of Vue component communication principle (2) Global state management Vuex

Vue component communication principle analysis (3) Provide/Inject principle analysis

Finally, friends who like me can also contact me through the public account “Jian Zhi Da Front-end”, or scan the qr code below to exchange experience and share. At the same time, I will regularly share some big front-end dry goods, so that our development will never get lost.