]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(teleport): proper children traversal when teleport is block root
authorEvan You <yyx990803@gmail.com>
Sat, 10 Oct 2020 19:40:31 +0000 (15:40 -0400)
committerEvan You <yyx990803@gmail.com>
Sat, 10 Oct 2020 20:07:30 +0000 (16:07 -0400)
fix #2324

packages/runtime-core/src/components/Teleport.ts
packages/runtime-core/src/renderer.ts

index 1b43061642c117523fb85e5aaae8958916dce3aa..48f6e04a63402acd272cc198bb0184e1628263b3 100644 (file)
@@ -5,7 +5,8 @@ import {
   MoveType,
   RendererElement,
   RendererNode,
-  RendererOptions
+  RendererOptions,
+  traverseStaticChildren
 } from '../renderer'
 import { VNode, VNodeArrayChildren, VNodeProps } from '../vnode'
 import { isString, ShapeFlags } from '@vue/shared'
@@ -142,16 +143,7 @@ export const TeleportImpl = {
         // even in block tree mode we need to make sure all root-level nodes
         // in the teleport inherit previous DOM references so that they can
         // be moved in future patches.
-        if (n2.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
-          const oldChildren = n1.children as VNode[]
-          const children = n2.children as VNode[]
-          for (let i = 0; i < children.length; i++) {
-            // only inherit for non-patched nodes (i.e. static ones)
-            if (!children[i].el) {
-              children[i].el = oldChildren[i].el
-            }
-          }
-        }
+        traverseStaticChildren(n1, n2, true)
       } else if (!optimized) {
         patchChildren(
           n1,
index 4cd7ccc27c0951208a869a1466d7a0d68196b178..997c015d8b861928b4ad160f2c66cb88360e9cff 100644 (file)
@@ -2190,39 +2190,6 @@ function baseCreateRenderer(
     return hostNextSibling((vnode.anchor || vnode.el)!)
   }
 
-  /**
-   * #1156
-   * When a component is HMR-enabled, we need to make sure that all static nodes
-   * inside a block also inherit the DOM element from the previous tree so that
-   * HMR updates (which are full updates) can retrieve the element for patching.
-   *
-   * #2080
-   * Inside keyed `template` fragment static children, if a fragment is moved,
-   * the children will always moved so that need inherit el form previous nodes
-   * to ensure correct moved position.
-   */
-  const traverseStaticChildren = (n1: VNode, n2: VNode, shallow = false) => {
-    const ch1 = n1.children
-    const ch2 = n2.children
-    if (isArray(ch1) && isArray(ch2)) {
-      for (let i = 0; i < ch1.length; i++) {
-        // this is only called in the optimized path so array children are
-        // guaranteed to be vnodes
-        const c1 = ch1[i] as VNode
-        const c2 = (ch2[i] = cloneIfMounted(ch2[i] as VNode))
-        if (c2.shapeFlag & ShapeFlags.ELEMENT && !c2.dynamicChildren) {
-          if (c2.patchFlag <= 0 || c2.patchFlag === PatchFlags.HYDRATE_EVENTS) {
-            c2.el = c1.el
-          }
-          if (!shallow) traverseStaticChildren(c1, c2)
-        }
-        if (__DEV__ && c2.type === Comment) {
-          c2.el = c1.el
-        }
-      }
-    }
-  }
-
   const render: RootRenderFunction = (vnode, container) => {
     if (vnode == null) {
       if (container._vnode) {
@@ -2276,6 +2243,42 @@ export function invokeVNodeHook(
   ])
 }
 
+/**
+ * #1156
+ * When a component is HMR-enabled, we need to make sure that all static nodes
+ * inside a block also inherit the DOM element from the previous tree so that
+ * HMR updates (which are full updates) can retrieve the element for patching.
+ *
+ * #2080
+ * Inside keyed `template` fragment static children, if a fragment is moved,
+ * the children will always moved so that need inherit el form previous nodes
+ * to ensure correct moved position.
+ */
+export function traverseStaticChildren(n1: VNode, n2: VNode, shallow = false) {
+  const ch1 = n1.children
+  const ch2 = n2.children
+  if (isArray(ch1) && isArray(ch2)) {
+    for (let i = 0; i < ch1.length; i++) {
+      // this is only called in the optimized path so array children are
+      // guaranteed to be vnodes
+      const c1 = ch1[i] as VNode
+      let c2 = ch2[i] as VNode
+      if (c2.shapeFlag & ShapeFlags.ELEMENT && !c2.dynamicChildren) {
+        if (c2.patchFlag <= 0 || c2.patchFlag === PatchFlags.HYDRATE_EVENTS) {
+          c2 = ch2[i] = cloneIfMounted(ch2[i] as VNode)
+          c2.el = c1.el
+        }
+        if (!shallow) traverseStaticChildren(c1, c2)
+      }
+      // also inherit for comment nodes, but not placeholders (e.g. v-if which
+      // would have received .el during block patch)
+      if (__DEV__ && c2.type === Comment && !c2.el) {
+        c2.el = c1.el
+      }
+    }
+  }
+}
+
 // https://en.wikipedia.org/wiki/Longest_increasing_subsequence
 function getSequence(arr: number[]): number[] {
   const p = arr.slice()