Просмотр исходного кода

fix child component nodes hook invocations

Evan You 10 лет назад
Родитель
Сommit
4c6b843f73
3 измененных файлов с 56 добавлено и 29 удалено
  1. 2 1
      src/runtime/dom-backend/modules/class.js
  2. 5 1
      src/runtime/vdom/component.js
  3. 49 27
      src/runtime/vdom/patch.js

+ 2 - 1
src/runtime/dom-backend/modules/class.js

@@ -12,7 +12,8 @@ function updateClass (oldVnode, vnode) {
   // or a child component root node
   if (vnode.child) {
     data = mergeClassData(vnode.child._vnode.data, data)
-  } else if (vnode.parent) {
+  }
+  if (vnode.parent) {
     data = mergeClassData(data, vnode.parent.data)
   }
 

+ 5 - 1
src/runtime/vdom/component.js

@@ -3,7 +3,7 @@ import VNode from './vnode'
 import { callHook } from '../instance/lifecycle'
 import { warn, isObject, hasOwn, hyphenate } from '../util/index'
 
-const hooks = { init, prepatch, insert }
+const hooks = { init, prepatch, insert, destroy }
 const hooksToMerge = Object.keys(hooks)
 
 export default function Component (Ctor, data, parent, children) {
@@ -97,6 +97,10 @@ function insert (vnode) {
   callHook(vnode.child, 'ready')
 }
 
+function destroy (vnode) {
+  vnode.child.$destroy()
+}
+
 function resolveAsyncComponent (factory, cb) {
   if (factory.resolved) {
     // cached

+ 49 - 27
src/runtime/vdom/patch.js

@@ -50,12 +50,14 @@ export default function createPatchFunction (backend) {
   }
 
   function createRmCb (childElm, listeners) {
-    return function remove () {
-      if (--listeners === 0) {
+    function remove () {
+      if (--remove.listeners === 0) {
         const parent = nodeOps.parentNode(childElm)
         nodeOps.removeChild(parent, childElm)
       }
     }
+    remove.listeners = listeners
+    return remove
   }
 
   function createElm (vnode, insertedVnodeQueue) {
@@ -68,7 +70,8 @@ export default function createPatchFunction (backend) {
       // component also has set the placeholder vnode's elm.
       // in that case we can just return the element and be done.
       if (isDef(i = vnode.child)) {
-        insertedVnodeQueue.push(vnode)
+        invokeCreateHooks(vnode, insertedVnodeQueue)
+        invokeCreateHooks(i._vnode, insertedVnodeQueue)
         return vnode.elm
       }
     }
@@ -85,18 +88,24 @@ export default function createPatchFunction (backend) {
       } else if (isPrimitive(vnode.text)) {
         nodeOps.appendChild(elm, nodeOps.createTextNode(vnode.text))
       }
-      for (i = 0; i < cbs.create.length; ++i) cbs.create[i](emptyNode, vnode)
-      i = vnode.data.hook // Reuse variable
-      if (isDef(i)) {
-        if (i.create) i.create(emptyNode, vnode)
-        if (i.insert) insertedVnodeQueue.push(vnode)
-      }
+      invokeCreateHooks(vnode, insertedVnodeQueue)
     } else {
       elm = vnode.elm = nodeOps.createTextNode(vnode.text)
     }
     return vnode.elm
   }
 
+  function invokeCreateHooks (vnode, insertedVnodeQueue) {
+    for (let i = 0; i < cbs.create.length; ++i) {
+      cbs.create[i](emptyNode, vnode)
+    }
+    i = vnode.data.hook // Reuse variable
+    if (isDef(i)) {
+      if (i.create) i.create(emptyNode, vnode)
+      if (i.insert) insertedVnodeQueue.push(vnode)
+    }
+  }
+
   function addVnodes (parentElm, before, vnodes, startIdx, endIdx, insertedVnodeQueue) {
     for (; startIdx <= endIdx; ++startIdx) {
       nodeOps.insertBefore(parentElm, createElm(vnodes[startIdx], insertedVnodeQueue), before)
@@ -114,30 +123,19 @@ export default function createPatchFunction (backend) {
           invokeDestroyHook(vnode.children[j])
         }
       }
-      if (isDef(i = vnode.child)) invokeDestroyHook(i._vnode)
+      if (isDef(i = vnode.child)) {
+        invokeDestroyHook(i._vnode)
+      }
     }
   }
 
   function removeVnodes (parentElm, vnodes, startIdx, endIdx) {
     for (; startIdx <= endIdx; ++startIdx) {
-      let i, listeners, rm
       let ch = vnodes[startIdx]
       if (isDef(ch)) {
         if (isDef(ch.tag)) {
-          // TODO: fix this hack
-          if (isDef(i = ch.child)) {
-            i.$destroy()
-            ch = i._vnode
-          }
           invokeDestroyHook(ch)
-          listeners = cbs.remove.length + 1
-          rm = createRmCb(ch.elm, listeners)
-          for (i = 0; i < cbs.remove.length; ++i) cbs.remove[i](ch, rm)
-          if (isDef(i = ch.data) && isDef(i = i.hook) && isDef(i = i.remove)) {
-            i(ch, rm)
-          } else {
-            rm()
-          }
+          invokeRemoveHook(ch)
         } else { // Text node
           nodeOps.removeChild(parentElm, ch.elm)
         }
@@ -145,6 +143,31 @@ export default function createPatchFunction (backend) {
     }
   }
 
+  function invokeRemoveHook (vnode, rm) {
+    let i
+    let listeners = cbs.remove.length + 1
+    if (!rm) {
+      // directly removing
+      rm = createRmCb(vnode.elm, listeners)
+    } else {
+      // we have a recursively passed down rm callback
+      // increase the listeners count
+      rm.listeners += listeners
+    }
+    // recursively invoke hooks on child component nodes
+    if (i = vnode.child) {
+      invokeRemoveHook(i._vnode, rm)
+    }
+    for (i = 0; i < cbs.remove.length; ++i) {
+      cbs.remove[i](vnode, rm)
+    }
+    if (isDef(i = vnode.data) && isDef(i = i.hook) && isDef(i = i.remove)) {
+      i(vnode, rm)
+    } else {
+      rm()
+    }
+  }
+
   function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue) {
     let oldStartIdx = 0
     let newStartIdx = 0
@@ -213,9 +236,8 @@ export default function createPatchFunction (backend) {
     if (isDef(i = vnode.data) && isDef(hook = i.hook) && isDef(i = hook.prepatch)) {
       i(oldVnode, vnode)
     }
-    // skip child component, which handles its own updates
-    // and nodes with v-pre
-    if (vnode.child || (isDef(i = vnode.data) && i.pre)) {
+    // skip nodes with v-pre
+    if (isDef(i = vnode.data) && i.pre) {
       return
     }
     let elm = vnode.elm = oldVnode.elm