From 86d3972855990c23f583a4b11b3c86fe04f1ab90 Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 29 Jun 2020 18:15:53 -0400 Subject: [PATCH] fix(transition-group): vue 2 compatible handling of transition-group w/ multiple v-for children fix #1126 --- .../src/components/BaseTransition.ts | 18 +++++++++++++----- .../src/components/TransitionGroup.ts | 5 ++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index a3ab079bc60..b1ee5da6851 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -15,7 +15,7 @@ import { warn } from '../warning' import { isKeepAlive } from './KeepAlive' import { toRaw } from '@vue/reactivity' import { callWithAsyncErrorHandling, ErrorCodes } from '../errorHandling' -import { ShapeFlags } from '@vue/shared' +import { ShapeFlags, PatchFlags } from '@vue/shared' import { onBeforeUnmount, onMounted } from '../apiLifecycle' import { RendererElement } from '../renderer' @@ -427,21 +427,29 @@ export function getTransitionRawChildren( keepComment: boolean = false ): VNode[] { let ret: VNode[] = [] + let keyedFragmentCount = 0 for (let i = 0; i < children.length; i++) { const child = children[i] // handle fragment children case, e.g. v-for if (child.type === Fragment) { + if (child.patchFlag & PatchFlags.KEYED_FRAGMENT) keyedFragmentCount++ ret = ret.concat( getTransitionRawChildren(child.children as VNode[], keepComment) ) } // comment placeholders should be skipped, e.g. v-if - else if ( - child.type !== Comment || - (child.type === Comment && keepComment) - ) { + else if (keepComment || child.type !== Comment) { 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 } diff --git a/packages/runtime-dom/src/components/TransitionGroup.ts b/packages/runtime-dom/src/components/TransitionGroup.ts index d056eb5b587..417f0b13eab 100644 --- a/packages/runtime-dom/src/components/TransitionGroup.ts +++ b/packages/runtime-dom/src/components/TransitionGroup.ts @@ -100,8 +100,7 @@ const TransitionGroupImpl = { const cssTransitionProps = resolveTransitionProps(rawProps) const tag = rawProps.tag || Fragment prevChildren = children - const slotChildren = slots.default ? slots.default() : [] - children = getTransitionRawChildren(slotChildren) + children = slots.default ? getTransitionRawChildren(slots.default()) : [] for (let i = 0; i < children.length; i++) { const child = children[i] @@ -126,7 +125,7 @@ const TransitionGroupImpl = { } } - return createVNode(tag, null, slotChildren) + return createVNode(tag, null, children) } } }