Skip to content

Commit ef2e737

Browse files
authored
fix(runtime-core): fix Transition for components with root-level v-if (#7678)
close #7649
1 parent 29425df commit ef2e737

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

packages/runtime-core/src/components/BaseTransition.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ export const BaseTransitionPropsValidators = {
135135
onAppearCancelled: TransitionHookValidator,
136136
}
137137

138+
const recursiveGetSubtree = (instance: ComponentInternalInstance): VNode => {
139+
const subTree = instance.subTree
140+
return subTree.component ? recursiveGetSubtree(subTree.component) : subTree
141+
}
142+
138143
const BaseTransitionImpl: ComponentOptions = {
139144
name: `BaseTransition`,
140145

@@ -213,7 +218,8 @@ const BaseTransitionImpl: ComponentOptions = {
213218
if (
214219
oldInnerChild &&
215220
oldInnerChild.type !== Comment &&
216-
!isSameVNodeType(innerChild, oldInnerChild)
221+
!isSameVNodeType(innerChild, oldInnerChild) &&
222+
recursiveGetSubtree(instance).type !== Comment
217223
) {
218224
const leavingHooks = resolveTransitionHooks(
219225
oldInnerChild,

packages/vue/__tests__/e2e/Transition.spec.ts

+77
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,83 @@ describe('e2e: Transition', () => {
12151215
E2E_TIMEOUT,
12161216
)
12171217

1218+
// issue https://github.com/vuejs/core/issues/7649
1219+
test(
1220+
'transition with v-if at component root-level',
1221+
async () => {
1222+
await page().evaluate(() => {
1223+
const { createApp, ref } = (window as any).Vue
1224+
createApp({
1225+
template: `
1226+
<div id="container">
1227+
<transition name="test" mode="out-in">
1228+
<component class="test" :is="view"></component>
1229+
</transition>
1230+
</div>
1231+
<button id="toggleBtn" @click="click">button</button>
1232+
<button id="changeViewBtn" @click="change">button</button>
1233+
`,
1234+
components: {
1235+
one: {
1236+
template: '<div v-if="false">one</div>',
1237+
},
1238+
two: {
1239+
template: '<div>two</div>',
1240+
},
1241+
},
1242+
setup: () => {
1243+
const toggle = ref(true)
1244+
const view = ref('one')
1245+
const click = () => (toggle.value = !toggle.value)
1246+
const change = () =>
1247+
(view.value = view.value === 'one' ? 'two' : 'one')
1248+
return { toggle, click, change, view }
1249+
},
1250+
}).mount('#app')
1251+
})
1252+
expect(await html('#container')).toBe('<!--v-if-->')
1253+
1254+
// change view -> 'two'
1255+
await page().evaluate(() => {
1256+
;(document.querySelector('#changeViewBtn') as any)!.click()
1257+
})
1258+
// enter
1259+
expect(await classWhenTransitionStart()).toStrictEqual([
1260+
'test',
1261+
'test-enter-from',
1262+
'test-enter-active',
1263+
])
1264+
await nextFrame()
1265+
expect(await classList('.test')).toStrictEqual([
1266+
'test',
1267+
'test-enter-active',
1268+
'test-enter-to',
1269+
])
1270+
await transitionFinish()
1271+
expect(await html('#container')).toBe('<div class="test">two</div>')
1272+
1273+
// change view -> 'one'
1274+
await page().evaluate(() => {
1275+
;(document.querySelector('#changeViewBtn') as any)!.click()
1276+
})
1277+
// leave
1278+
expect(await classWhenTransitionStart()).toStrictEqual([
1279+
'test',
1280+
'test-leave-from',
1281+
'test-leave-active',
1282+
])
1283+
await nextFrame()
1284+
expect(await classList('.test')).toStrictEqual([
1285+
'test',
1286+
'test-leave-active',
1287+
'test-leave-to',
1288+
])
1289+
await transitionFinish()
1290+
expect(await html('#container')).toBe('<!--v-if-->')
1291+
},
1292+
E2E_TIMEOUT,
1293+
)
1294+
12181295
// #3716
12191296
test(
12201297
'wrapping transition + fallthrough attrs',

0 commit comments

Comments
 (0)