From: Evan You Date: Sat, 10 Oct 2020 19:40:31 +0000 (-0400) Subject: fix(teleport): proper children traversal when teleport is block root X-Git-Tag: v3.0.1~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2ae3b26679faf2d5393998ba806b99748679195a;p=thirdparty%2Fvuejs%2Fcore.git fix(teleport): proper children traversal when teleport is block root fix #2324 --- diff --git a/packages/runtime-core/src/components/Teleport.ts b/packages/runtime-core/src/components/Teleport.ts index 1b43061642..48f6e04a63 100644 --- a/packages/runtime-core/src/components/Teleport.ts +++ b/packages/runtime-core/src/components/Teleport.ts @@ -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, diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 4cd7ccc27c..997c015d8b 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -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()