diff --git a/packages/runtime-dom/src/components/TransitionGroup.ts b/packages/runtime-dom/src/components/TransitionGroup.ts index fc5d260b91e..5ca4b3b3ba3 100644 --- a/packages/runtime-dom/src/components/TransitionGroup.ts +++ b/packages/runtime-dom/src/components/TransitionGroup.ts @@ -112,7 +112,9 @@ const TransitionGroupImpl: ComponentOptions = { tag = 'span' } - prevChildren = children + prevChildren = + children && + children.filter((c: VNode) => c.el && c.el.getBoundingClientRect) children = slots.default ? getTransitionRawChildren(slots.default()) : [] for (let i = 0; i < children.length; i++) { diff --git a/packages/vue/__tests__/e2e/TransitionGroup.spec.ts b/packages/vue/__tests__/e2e/TransitionGroup.spec.ts index 434735b5e9e..360b40162a4 100644 --- a/packages/vue/__tests__/e2e/TransitionGroup.spec.ts +++ b/packages/vue/__tests__/e2e/TransitionGroup.spec.ts @@ -508,4 +508,51 @@ describe('e2e: TransitionGroup', () => { expect(` children must be keyed`).toHaveBeenWarned() }) + + test('TransitionGroup on child components with empty root node', async () => { + const pageTemp = await page() + pageTemp.evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ + + +
+ + + `, + components: { + Comp: { + template: '
one
' + } + }, + setup: () => { + const items = ref(['1', '2']) + const click = () => { + setTimeout(() => { + items.value.splice(0, 1) + }) + } + const change = () => { + items.value.push('3') + } + return { items, click, change } + } + }).mount('#app') + }) + + expect(await html('#container')).toBe('') + // splice + await htmlWhenTransitionStart() + await transitionFinish() + expect(await html('#container')).toBe(``) + // push back + await page().evaluate(() => { + ;(document.querySelector('#pushBtn') as any)!.click() + }) + await transitionFinish() + expect(await html('#container')).toBe('') + }) })