Ver código fonte

fix listeners

Evan You 10 anos atrás
pai
commit
23c253012f

+ 3 - 3
src/runtime/instance/events.js

@@ -4,9 +4,9 @@ import { updateListeners } from '../vdom/helpers'
 export function initEvents (vm) {
   vm._events = Object.create(null)
   // init parent attached events
-  const parentData = vm.$options._renderData
-  if (parentData && parentData.on) {
-    updateListeners(parentData.on, {}, (event, handler) => {
+  const listeners = vm.$options._parentListeners
+  if (listeners) {
+    updateListeners(listeners, {}, (event, handler) => {
       vm.$on(event, handler)
     })
   }

+ 10 - 2
src/runtime/instance/render.js

@@ -1,6 +1,6 @@
 import { observerState } from '../observer/index'
 import createElement from '../vdom/create-element'
-import { flatten } from '../vdom/helpers'
+import { flatten, updateListeners } from '../vdom/helpers'
 import {
   bind,
   resolveAsset,
@@ -96,7 +96,7 @@ export function renderMixin (Vue) {
     }
   }
 
-  Vue.prototype._updateFromParent = function (propsData, parentVnode, children) {
+  Vue.prototype._updateFromParent = function (propsData, listeners, parentVnode, children) {
     this.$options._parentVnode = parentVnode
     this.$options._renderChildren = children
     // update props
@@ -109,6 +109,14 @@ export function renderMixin (Vue) {
       }
       observerState.shouldConvert = true
     }
+    // update listeners
+    if (listeners) {
+      const oldListeners = this.$options._parentListeners
+      this.$options._parentListeners = listeners
+      updateListeners(listeners, oldListeners || {}, (event, handler) => {
+        this.$on(event, handler)
+      })
+    }
   }
 
   Vue.prototype._render = function () {

+ 47 - 39
src/runtime/vdom/component.js

@@ -3,44 +3,7 @@ import VNode from './vnode'
 import { callHook } from '../instance/lifecycle'
 import { warn, isObject, hasOwn, hyphenate } from '../util/index'
 
-const hooks = {
-  init (vnode) {
-    const { Ctor, propsData, parent, children } = vnode.componentOptions
-    const child = new Ctor({
-      parent,
-      propsData,
-      _parentVnode: vnode,
-      _renderChildren: children
-    })
-    // the child sets the parent vnode's elm when mounted
-    // and when updated.
-    child.$mount()
-    vnode.child = child
-  },
-
-  prepatch (oldVnode, vnode) {
-    const oldCtor = oldVnode.componentOptions.Ctor
-    const { Ctor, propsData, children } = vnode.componentOptions
-    if (Ctor !== oldCtor) {
-      // component changed, teardown and create new
-      // TODO: keep-alive?
-      oldVnode.child.$destroy()
-      hooks.init(vnode)
-    } else {
-      vnode.child = oldVnode.child
-      vnode.child._updateFromParent(
-        propsData, // updated props
-        vnode, // new parent vnode
-        children // new children
-      )
-    }
-  },
-
-  insert (vnode) {
-    callHook(vnode.child, 'ready')
-  }
-}
-
+const hooks = { init, prepatch, insert }
 const hooksToMerge = Object.keys(hooks)
 
 export default function Component (Ctor, data, parent, children) {
@@ -83,12 +46,57 @@ export default function Component (Ctor, data, parent, children) {
   // extract props
   const propsData = extractProps(data, Ctor)
 
+  // extract listeners, since these needs to be treated as
+  // child component listeners instead of DOM listeners
+  const listeners = data.on
+  if (listeners) {
+    data.on = null
+  }
+
   // return a placeholder vnode
   const vnode = VNode('vue-component-' + Ctor.cid, data)
-  vnode.componentOptions = { Ctor, propsData, parent, children }
+  vnode.componentOptions = { Ctor, propsData, listeners, parent, children }
   return vnode
 }
 
+function init (vnode) {
+  const { Ctor, propsData, listeners, parent, children } = vnode.componentOptions
+  const child = new Ctor({
+    parent,
+    propsData,
+    _parentVnode: vnode,
+    _parentListeners: listeners,
+    _renderChildren: children
+  })
+  // the child sets the parent vnode's elm when mounted
+  // and when updated.
+  child.$mount()
+  vnode.child = child
+}
+
+function prepatch (oldVnode, vnode) {
+  const oldCtor = oldVnode.componentOptions.Ctor
+  const { Ctor, listeners, propsData, children } = vnode.componentOptions
+  if (Ctor !== oldCtor) {
+    // component changed, teardown and create new
+    // TODO: keep-alive?
+    oldVnode.child.$destroy()
+    hooks.init(vnode)
+  } else {
+    vnode.child = oldVnode.child
+    vnode.child._updateFromParent(
+      propsData, // updated props
+      listeners, // updated listeners
+      vnode, // new parent vnode
+      children // new children
+    )
+  }
+}
+
+function insert (vnode) {
+  callHook(vnode.child, 'ready')
+}
+
 function resolveAsyncComponent (factory, cb) {
   if (factory.resolved) {
     // cached