Skip to content

Commit

Permalink
fix(teleport): proper children traversal when teleport is block root
Browse files Browse the repository at this point in the history
fix #2324
  • Loading branch information
yyx990803 committed Oct 10, 2020
1 parent 9bb1414 commit 2ae3b26
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 44 deletions.
14 changes: 3 additions & 11 deletions packages/runtime-core/src/components/Teleport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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,
Expand Down
69 changes: 36 additions & 33 deletions packages/runtime-core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 2ae3b26

Please sign in to comment.