fix(transition-group): vue 2 compatible handling of transition-group w/ multiple v-for children

fix #1126
This commit is contained in:
Evan You 2020-06-29 18:15:53 -04:00
parent d32aed0906
commit 86d3972855
2 changed files with 15 additions and 8 deletions

View File

@ -15,7 +15,7 @@ import { warn } from '../warning'
import { isKeepAlive } from './KeepAlive' import { isKeepAlive } from './KeepAlive'
import { toRaw } from '@vue/reactivity' import { toRaw } from '@vue/reactivity'
import { callWithAsyncErrorHandling, ErrorCodes } from '../errorHandling' import { callWithAsyncErrorHandling, ErrorCodes } from '../errorHandling'
import { ShapeFlags } from '@vue/shared' import { ShapeFlags, PatchFlags } from '@vue/shared'
import { onBeforeUnmount, onMounted } from '../apiLifecycle' import { onBeforeUnmount, onMounted } from '../apiLifecycle'
import { RendererElement } from '../renderer' import { RendererElement } from '../renderer'
@ -427,21 +427,29 @@ export function getTransitionRawChildren(
keepComment: boolean = false keepComment: boolean = false
): VNode[] { ): VNode[] {
let ret: VNode[] = [] let ret: VNode[] = []
let keyedFragmentCount = 0
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
const child = children[i] const child = children[i]
// handle fragment children case, e.g. v-for // handle fragment children case, e.g. v-for
if (child.type === Fragment) { if (child.type === Fragment) {
if (child.patchFlag & PatchFlags.KEYED_FRAGMENT) keyedFragmentCount++
ret = ret.concat( ret = ret.concat(
getTransitionRawChildren(child.children as VNode[], keepComment) getTransitionRawChildren(child.children as VNode[], keepComment)
) )
} }
// comment placeholders should be skipped, e.g. v-if // comment placeholders should be skipped, e.g. v-if
else if ( else if (keepComment || child.type !== Comment) {
child.type !== Comment ||
(child.type === Comment && keepComment)
) {
ret.push(child) ret.push(child)
} }
} }
// #1126 if a transition children list contains multiple sub fragments, these
// fragments will be merged into a flat children array. Since each v-for
// fragment may contain different static bindings inside, we need to de-top
// these children to force full diffs to ensure correct behavior.
if (keyedFragmentCount > 1) {
for (let i = 0; i < ret.length; i++) {
ret[i].patchFlag = PatchFlags.BAIL
}
}
return ret return ret
} }

View File

@ -100,8 +100,7 @@ const TransitionGroupImpl = {
const cssTransitionProps = resolveTransitionProps(rawProps) const cssTransitionProps = resolveTransitionProps(rawProps)
const tag = rawProps.tag || Fragment const tag = rawProps.tag || Fragment
prevChildren = children prevChildren = children
const slotChildren = slots.default ? slots.default() : [] children = slots.default ? getTransitionRawChildren(slots.default()) : []
children = getTransitionRawChildren(slotChildren)
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
const child = children[i] const child = children[i]
@ -126,7 +125,7 @@ const TransitionGroupImpl = {
} }
} }
return createVNode(tag, null, slotChildren) return createVNode(tag, null, children)
} }
} }
} }