Evan You 10 лет назад
Родитель
Сommit
be9e16e20f
3 измененных файлов с 37 добавлено и 21 удалено
  1. 16 5
      src/runtime/instance/render.js
  2. 2 2
      src/runtime/vdom/index.js
  3. 19 14
      src/runtime/vdom/modules/events.js

+ 16 - 5
src/runtime/instance/render.js

@@ -1,6 +1,6 @@
 import Watcher from '../observer/watcher'
 import { query, resolveAsset, hyphenate, hasOwn } from '../util/index'
-import { createElement, patch } from '../vdom/index'
+import { createElement, patch, updateListeners } from '../vdom/index'
 import { callHook } from './lifecycle'
 
 export const renderState = {
@@ -36,8 +36,7 @@ function resolveSlots (vm, children) {
   }
 }
 
-function mergeParentData (vm, data, parentData) {
-  // attrs
+function mergeParentAttrs (vm, data, parentData) {
   if (parentData.attrs) {
     const props = vm.$options.props
     for (let key in parentData.attrs) {
@@ -46,12 +45,22 @@ function mergeParentData (vm, data, parentData) {
       }
     }
   }
-  // directives
+}
+
+function mergeParentDirectives (vm, data, parentData) {
   if (parentData.directives) {
     data.directives = parentData.directives.conact(data.directives || [])
   }
 }
 
+function updateParentCallbacks (vm, data, parentData) {
+  if (parentData.on) {
+    updateListeners(parentData.on, data.on || {}, (event, handler) => {
+      vm.$on(event, handler)
+    })
+  }
+}
+
 export function renderMixin (Vue) {
   // shorthands used in render functions
   Vue.prototype.__h__ = createElement
@@ -98,7 +107,9 @@ export function renderMixin (Vue) {
     const data = vnode.data
     const parentData = this._renderData
     if (parentData) {
-      mergeParentData(this, data, parentData)
+      mergeParentAttrs(this, data, parentData)
+      mergeParentDirectives(this, data, parentData)
+      updateParentCallbacks(this, data, parentData)
     }
     renderState.activeInstance = prev
     return vnode

+ 2 - 2
src/runtime/vdom/index.js

@@ -10,7 +10,7 @@ import classes from './modules/class'
 import style from './modules/style'
 import props from './modules/props'
 import attrs from './modules/attrs'
-import events from './modules/events'
+import events, { updateListeners } from './modules/events'
 import directives from './modules/directives'
 
 const patch = createPatchFunction([
@@ -22,4 +22,4 @@ const patch = createPatchFunction([
   directives
 ])
 
-export { patch, createElement }
+export { patch, createElement, updateListeners }

+ 19 - 14
src/runtime/vdom/modules/events.js

@@ -1,3 +1,5 @@
+import { isArray } from '../../util/index'
+
 function arrInvoker (arr) {
   return function (ev) {
     for (let i = 0; i < arr.length; i++) {
@@ -10,29 +12,24 @@ function fnInvoker (o) {
   return function (ev) { o.fn(ev) }
 }
 
-function updateEventListeners (oldVnode, vnode) {
+export function updateListeners (on, oldOn, add) {
   let name, cur, old, event, capture
-  const elm = vnode.elm
-  const oldOn = oldVnode.data.on || {}
-  const on = vnode.data.on
-  if (!on) return
   for (name in on) {
     cur = on[name]
     old = oldOn[name]
     if (old === undefined) {
       capture = name.charAt(0) === '!'
       event = capture ? name.slice(1) : name
-      if (Array.isArray(cur)) {
-        elm.addEventListener(event, arrInvoker(cur), capture)
+      if (isArray(cur)) {
+        add(event, arrInvoker(cur), capture)
       } else {
-        cur = {fn: cur}
+        cur = { fn: cur }
         on[name] = cur
-        elm.addEventListener(event, fnInvoker(cur), capture)
+        add(event, fnInvoker(cur), capture)
       }
-    } else if (Array.isArray(old)) {
-      // Deliberately modify old array since it's captured in closure created with `arrInvoker`
+    } else if (isArray(old)) {
       old.length = cur.length
-      for (var i = 0; i < old.length; ++i) old[i] = cur[i]
+      for (let i = 0; i < old.length; i++) old[i] = cur[i]
       on[name] = old
     } else {
       old.fn = cur
@@ -41,7 +38,15 @@ function updateEventListeners (oldVnode, vnode) {
   }
 }
 
+function updateDOMListeners (oldVnode, vnode) {
+  const on = vnode.data.on
+  const oldOn = oldVnode.data.on || {}
+  updateListeners(on, oldOn, (event, handler, capture) => {
+    vnode.elm.addEventListener(event, handler, capture)
+  })
+}
+
 export default {
-  create: updateEventListeners,
-  update: updateEventListeners
+  create: updateDOMListeners,
+  update: updateDOMListeners
 }