Skip to content

Commit 767d212

Browse files
authored
fix(transition): fix broken leave transition on dev root fragment (#5268)
1 parent 71c9536 commit 767d212

File tree

2 files changed

+88
-4
lines changed

2 files changed

+88
-4
lines changed

packages/runtime-core/src/renderer.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2159,7 +2159,23 @@ function baseCreateRenderer(
21592159
const remove: RemoveFn = vnode => {
21602160
const { type, el, anchor, transition } = vnode
21612161
if (type === Fragment) {
2162-
removeFragment(el!, anchor!)
2162+
if (
2163+
__DEV__ &&
2164+
vnode.patchFlag > 0 &&
2165+
vnode.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT &&
2166+
transition &&
2167+
!transition.persisted
2168+
) {
2169+
;(vnode.children as VNode[]).forEach(child => {
2170+
if (child.type === Comment) {
2171+
hostRemove(child.el!)
2172+
} else {
2173+
remove(child)
2174+
}
2175+
})
2176+
} else {
2177+
removeFragment(el!, anchor!)
2178+
}
21632179
return
21642180
}
21652181

packages/vue/__tests__/Transition.spec.ts

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,9 +1979,7 @@ describe('e2e: Transition', () => {
19791979
</div>
19801980
`
19811981
}).mount(document.createElement('div'))
1982-
expect(
1983-
`invalid <transition> mode: none`
1984-
).toHaveBeenWarned()
1982+
expect(`invalid <transition> mode: none`).toHaveBeenWarned()
19851983
})
19861984

19871985
// #3227
@@ -2023,4 +2021,74 @@ describe('e2e: Transition', () => {
20232021
expect(outerSpy).toHaveBeenCalledTimes(1)
20242022
expect(root.innerHTML).toBe(`<!---->`)
20252023
})
2024+
2025+
test(
2026+
'should work with dev root fragment',
2027+
async () => {
2028+
await page().evaluate(() => {
2029+
const { createApp, ref } = (window as any).Vue
2030+
createApp({
2031+
components: {
2032+
Comp: {
2033+
template: `
2034+
<!-- Broken! -->
2035+
<div><slot /></div>
2036+
`
2037+
}
2038+
},
2039+
template: `
2040+
<div id="container">
2041+
<transition>
2042+
<Comp class="test" v-if="toggle">
2043+
<div>content</div>
2044+
</Comp>
2045+
</transition>
2046+
</div>
2047+
<button id="toggleBtn" @click="click">button</button>
2048+
`,
2049+
setup: () => {
2050+
const toggle = ref(true)
2051+
const click = () => (toggle.value = !toggle.value)
2052+
return { toggle, click }
2053+
}
2054+
}).mount('#app')
2055+
})
2056+
expect(await html('#container')).toBe(
2057+
'<!-- Broken! --><div class="test"><div>content</div></div>'
2058+
)
2059+
2060+
// leave
2061+
expect(await classWhenTransitionStart()).toStrictEqual([
2062+
'test',
2063+
'v-leave-from',
2064+
'v-leave-active'
2065+
])
2066+
await nextFrame()
2067+
expect(await classList('.test')).toStrictEqual([
2068+
'test',
2069+
'v-leave-active',
2070+
'v-leave-to'
2071+
])
2072+
await transitionFinish()
2073+
expect(await html('#container')).toBe('<!--v-if-->')
2074+
2075+
// enter
2076+
expect(await classWhenTransitionStart()).toStrictEqual([
2077+
'test',
2078+
'v-enter-from',
2079+
'v-enter-active'
2080+
])
2081+
await nextFrame()
2082+
expect(await classList('.test')).toStrictEqual([
2083+
'test',
2084+
'v-enter-active',
2085+
'v-enter-to'
2086+
])
2087+
await transitionFinish()
2088+
expect(await html('#container')).toBe(
2089+
'<!-- Broken! --><div class="test"><div>content</div></div>'
2090+
)
2091+
},
2092+
E2E_TIMEOUT
2093+
)
20262094
})

0 commit comments

Comments
 (0)