Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 45990ce

Browse files
authored
fix(transition): preserve placeholder for conditional explicit default slots (#14748)
close #14727
1 parent 6a61f44 commit 45990ce

2 files changed

Lines changed: 61 additions & 2 deletions

File tree

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
type VNode,
1111
type VNodeArrayChildren,
1212
cloneVNode,
13+
createCommentVNode,
1314
isSameVNodeType,
1415
} from '../vnode'
1516
import { warn } from '../warning'
@@ -155,11 +156,18 @@ const BaseTransitionImpl: ComponentOptions = {
155156
return () => {
156157
const children =
157158
slots.default && getTransitionRawChildren(slots.default(), true)
158-
if (!children || !children.length) {
159+
const child =
160+
children && children.length
161+
? findNonCommentChild(children)
162+
: // Keep explicit default-slot conditionals on the same transition path
163+
// as regular v-if branches, which render a comment placeholder.
164+
instance.subTree
165+
? createCommentVNode()
166+
: undefined
167+
if (!child) {
159168
return
160169
}
161170

162-
const child: VNode = findNonCommentChild(children)
163171
// there's no need to track reactivity for these props so use the raw
164172
// props for a bit better perf
165173
const rawProps = toRaw(props)

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,6 +1428,57 @@ describe('e2e: Transition', () => {
14281428
},
14291429
E2E_TIMEOUT,
14301430
)
1431+
1432+
// #14727
1433+
test(
1434+
'explicit default slot template can toggle again before leave finishes',
1435+
async () => {
1436+
const spy = vi.fn()
1437+
const currentPage = page()
1438+
currentPage.on('pageerror', spy)
1439+
1440+
await page().evaluate(() => {
1441+
const { createApp, ref } = (window as any).Vue
1442+
createApp({
1443+
template: `
1444+
<div id="container">
1445+
<transition name="test">
1446+
<template v-if="show" #>
1447+
<div class="test">text</div>
1448+
</template>
1449+
</transition>
1450+
</div>
1451+
<button id="toggleBtn" @click="show = !show">button</button>
1452+
`,
1453+
setup: () => {
1454+
const show = ref(true)
1455+
return { show }
1456+
},
1457+
}).mount('#app')
1458+
})
1459+
1460+
expect(await html('#container')).toBe('<div class="test">text</div>')
1461+
1462+
await click('#toggleBtn')
1463+
await nextTick()
1464+
await click('#toggleBtn')
1465+
1466+
expect(
1467+
await page().$$eval('#container .test', nodes =>
1468+
nodes.map(node => node.className),
1469+
),
1470+
).toStrictEqual(['test test-enter-from test-enter-active'])
1471+
1472+
await nextFrame()
1473+
await transitionFinish()
1474+
await nextFrame()
1475+
1476+
expect(spy).not.toHaveBeenCalled()
1477+
currentPage.off('pageerror', spy)
1478+
expect(await html('#container')).toBe('<div class="test">text</div>')
1479+
},
1480+
E2E_TIMEOUT,
1481+
)
14311482
})
14321483

14331484
describe('transition with KeepAlive', () => {

0 commit comments

Comments
 (0)