Skip to content

Commit df059f8

Browse files
authored
fix(transition): prevent enter if leave is in progress (#14443)
close #12091 close #12133
1 parent 09dec96 commit df059f8

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,8 @@ export function resolveTransitionHooks(
400400
},
401401

402402
enter(el) {
403+
// prevent enter if leave is in progress
404+
if (leavingVNodesCache[key] === vnode) return
403405
let hook = onEnter
404406
let afterHook = onAfterEnter
405407
let cancelHook = onEnterCancelled

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

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3341,6 +3341,76 @@ describe('e2e: Transition', () => {
33413341
E2E_TIMEOUT,
33423342
)
33433343

3344+
// #12091
3345+
test(
3346+
'prevent enter when leaving',
3347+
async () => {
3348+
const hooks: string[] = []
3349+
const pushHook = (hook: string) => hooks.push(hook)
3350+
await page().exposeFunction('pushHook', pushHook)
3351+
await page().evaluate(() => {
3352+
const { pushHook } = window as any
3353+
const { createApp, ref } = (window as any).Vue
3354+
const visible = ref(true)
3355+
createApp({
3356+
components: {
3357+
Comp: {
3358+
setup() {
3359+
visible.value = false
3360+
return () => null
3361+
},
3362+
},
3363+
},
3364+
template: `
3365+
<div id="content" v-if="toggle">
3366+
<div id="container">
3367+
<transition
3368+
appear
3369+
@before-enter="pushHook('beforeEnter')"
3370+
@enter="pushHook('enter')"
3371+
@enter-cancelled="pushHook('enterCancelled')"
3372+
@after-enter="pushHook('afterEnter')"
3373+
@before-leave="pushHook('beforeLeave')"
3374+
@leave="pushHook('leave')"
3375+
@after-leave="pushHook('afterLeave')"
3376+
>
3377+
<div v-if="visible">content</div>
3378+
</transition>
3379+
</div>
3380+
<Comp />
3381+
</div>
3382+
<button id="toggleBtn" @click="click">button</button>
3383+
`,
3384+
setup: () => {
3385+
const toggle = ref(false)
3386+
const click = () => (toggle.value = !toggle.value)
3387+
return {
3388+
toggle,
3389+
click,
3390+
pushHook,
3391+
visible,
3392+
}
3393+
},
3394+
}).mount('#app')
3395+
})
3396+
3397+
await click('#toggleBtn')
3398+
await nextTick()
3399+
await transitionFinish()
3400+
3401+
expect(hooks).toStrictEqual([
3402+
'beforeEnter',
3403+
'beforeLeave',
3404+
'leave',
3405+
'afterLeave',
3406+
])
3407+
expect(await html('#content')).toBe(
3408+
'<div id="container"><!--v-if--></div><!---->',
3409+
)
3410+
},
3411+
E2E_TIMEOUT,
3412+
)
3413+
33443414
// https://github.com/vuejs/core/issues/12181#issuecomment-2414380955
33453415
describe('not leaking', async () => {
33463416
test('switching VNodes', async () => {

0 commit comments

Comments
 (0)