From ef2e737577de42ea38771403f8a4dee8c892daa5 Mon Sep 17 00:00:00 2001 From: AlexVagrant <1113629699@qq.com> Date: Tue, 4 Jun 2024 22:06:07 +0800 Subject: [PATCH] fix(runtime-core): fix Transition for components with root-level v-if (#7678) close #7649 --- .../src/components/BaseTransition.ts | 8 +- packages/vue/__tests__/e2e/Transition.spec.ts | 77 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 070418a19a0..848369074ea 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -135,6 +135,11 @@ export const BaseTransitionPropsValidators = { onAppearCancelled: TransitionHookValidator, } +const recursiveGetSubtree = (instance: ComponentInternalInstance): VNode => { + const subTree = instance.subTree + return subTree.component ? recursiveGetSubtree(subTree.component) : subTree +} + const BaseTransitionImpl: ComponentOptions = { name: `BaseTransition`, @@ -213,7 +218,8 @@ const BaseTransitionImpl: ComponentOptions = { if ( oldInnerChild && oldInnerChild.type !== Comment && - !isSameVNodeType(innerChild, oldInnerChild) + !isSameVNodeType(innerChild, oldInnerChild) && + recursiveGetSubtree(instance).type !== Comment ) { const leavingHooks = resolveTransitionHooks( oldInnerChild, diff --git a/packages/vue/__tests__/e2e/Transition.spec.ts b/packages/vue/__tests__/e2e/Transition.spec.ts index 4fe78ae8ab0..26c39a0ecc0 100644 --- a/packages/vue/__tests__/e2e/Transition.spec.ts +++ b/packages/vue/__tests__/e2e/Transition.spec.ts @@ -1215,6 +1215,83 @@ describe('e2e: Transition', () => { E2E_TIMEOUT, ) + // issue https://github.com/vuejs/core/issues/7649 + test( + 'transition with v-if at component root-level', + async () => { + await page().evaluate(() => { + const { createApp, ref } = (window as any).Vue + createApp({ + template: ` +
+ + + +
+ + + `, + components: { + one: { + template: '
one
', + }, + two: { + template: '
two
', + }, + }, + setup: () => { + const toggle = ref(true) + const view = ref('one') + const click = () => (toggle.value = !toggle.value) + const change = () => + (view.value = view.value === 'one' ? 'two' : 'one') + return { toggle, click, change, view } + }, + }).mount('#app') + }) + expect(await html('#container')).toBe('') + + // change view -> 'two' + await page().evaluate(() => { + ;(document.querySelector('#changeViewBtn') as any)!.click() + }) + // enter + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-enter-from', + 'test-enter-active', + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-enter-active', + 'test-enter-to', + ]) + await transitionFinish() + expect(await html('#container')).toBe('
two
') + + // change view -> 'one' + await page().evaluate(() => { + ;(document.querySelector('#changeViewBtn') as any)!.click() + }) + // leave + expect(await classWhenTransitionStart()).toStrictEqual([ + 'test', + 'test-leave-from', + 'test-leave-active', + ]) + await nextFrame() + expect(await classList('.test')).toStrictEqual([ + 'test', + 'test-leave-active', + 'test-leave-to', + ]) + await transitionFinish() + expect(await html('#container')).toBe('') + }, + E2E_TIMEOUT, + ) + // #3716 test( 'wrapping transition + fallthrough attrs',