关于自定义事件$emit的一个问题

来源:8-9 event(8)

knightBUTnotYONNG

2019-03-20

 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) {
      cbs = cbs.length > 1 ? toArray(cbs) : cbs
      const args = toArray(arguments, 1)
      for (let i = 0, l = cbs.length; i < l; i++) {
        try {
          cbs[i].apply(vm, args)
        } catch (e) {
          handleError(e, vm, `event handler for "${event}"`)
        }
      }
    }
    return vm
  }```
$emit派发事件是for循环里调用cbs.apply(vm(子组件实例),args),但是老师为什么你说这是在父组件环境下调用的呢?
写回答

2回答

ustbhuangyi

2019-03-20

首先 $emit 是往当前实例上派发一个事件。
其次,通常我们说组件通讯的时候,子组件想通知父组件的时候,通常会执行 $emit 派发一个事件,但由于我们的子组件是写在父组件中的,那么这个事件侦听函数的执行作用域也就是父组件了。

0
2
knightBUTnotYONNG
非常感谢!
2019-03-20
共2条回复

前端工程师666777888

2021-04-20

cbs.apply(vm(子组件实例),args)。

按理说,cbs中的this,确实是子组件实例。

但是vue框架处理了,处理过程如下:

在this.$emit()时,会执行cbs.apply(vm(子组件实例),args),但是此时的cbs是createFnInvoker()函数中的invoker()函数并不是我们写的回调函数。在invoker()函数中,会把cbs指向我们的回调函数,在执行时会变成这样cbs.apply(null,args),已经变成null了。所以cbs中的this还是指向父组件

0
0

Vue.js 源码深入解析 深入理解Vue实现原理

全方位讲解 Vue.js 源码,进阶高级工程师

4984 学习 · 1037 问题

查看课程