diff --git a/packages/runtime-core/src/components/Suspense.ts b/packages/runtime-core/src/components/Suspense.ts index 0fa07d9beec..031a3dcfb11 100644 --- a/packages/runtime-core/src/components/Suspense.ts +++ b/packages/runtime-core/src/components/Suspense.ts @@ -432,7 +432,7 @@ function createSuspenseBoundary( m: move, um: unmount, n: next, - o: { parentNode, remove } + o: { nextSibling, parentNode, remove } } = rendererInternals // if set `suspensible: true`, set the current suspense as a dep of parent suspense @@ -494,28 +494,42 @@ function createSuspenseBoundary( if (suspense.isHydrating) { suspense.isHydrating = false } else if (!resume) { + const anchorCands: RendererNode[] = [] + if (activeBranch) { + for (let node = next(activeBranch); node; node = nextSibling(node)) { + anchorCands.push(node) + } + } + + // this is initial anchor on mount + const { anchor: initialAnchor } = suspense + const delayEnter = activeBranch && pendingBranch!.transition && pendingBranch!.transition.mode === 'out-in' + if (delayEnter) { activeBranch!.transition!.afterLeave = () => { if (pendingId === suspense.pendingId) { + const anchor = + anchorCands.find(x => parentNode(x) === container) || + initialAnchor move(pendingBranch!, container, anchor, MoveType.ENTER) } } } - // this is initial anchor on mount - let { anchor } = suspense + // unmount current active tree if (activeBranch) { // if the fallback tree was mounted, it may have been moved // as part of a parent suspense. get the latest anchor for insertion - anchor = next(activeBranch) unmount(activeBranch, parentComponent, suspense, true) } if (!delayEnter) { // move content from off-dom container to actual container + const anchor = + anchorCands.find(x => parentNode(x) === container) || initialAnchor move(pendingBranch!, container, anchor, MoveType.ENTER) } } diff --git a/packages/vue/__tests__/e2e/Transition.spec.ts b/packages/vue/__tests__/e2e/Transition.spec.ts index 50b3524fdb7..1aaee555a2c 100644 --- a/packages/vue/__tests__/e2e/Transition.spec.ts +++ b/packages/vue/__tests__/e2e/Transition.spec.ts @@ -1432,6 +1432,16 @@ describe('e2e: Transition', () => { // ) await transitionFinish() expect(await html('#container')).toBe('
two
') + + // toggle rapidly #8105 + await click('#toggleBtn') + await nextFrame() + await click('#toggleBtn') + + // wait for awhile + await transitionFinish(duration * 3) + + expect(await html('#container')).toBe('
two
') }, E2E_TIMEOUT )