瀏覽代碼

fix(runtime-core): Suspense get anchor properly in Transition (#9309)

close #8105
edison 2 年之前
父節點
當前提交
65f3fe2731
共有 2 個文件被更改,包括 73 次插入3 次删除
  1. 7 3
      packages/runtime-core/src/components/Suspense.ts
  2. 66 0
      packages/vue/__tests__/e2e/Transition.spec.ts

+ 7 - 3
packages/runtime-core/src/components/Suspense.ts

@@ -504,7 +504,12 @@ function createSuspenseBoundary(
         if (delayEnter) {
           activeBranch!.transition!.afterLeave = () => {
             if (pendingId === suspense.pendingId) {
-              move(pendingBranch!, container, anchor, MoveType.ENTER)
+              move(
+                pendingBranch!,
+                container,
+                next(activeBranch!),
+                MoveType.ENTER
+              )
               queuePostFlushCb(effects)
             }
           }
@@ -577,7 +582,6 @@ function createSuspenseBoundary(
       // invoke @fallback event
       triggerEvent(vnode, 'onFallback')
 
-      const anchor = next(activeBranch!)
       const mountFallback = () => {
         if (!suspense.isInFallback) {
           return
@@ -587,7 +591,7 @@ function createSuspenseBoundary(
           null,
           fallbackVNode,
           container,
-          anchor,
+          next(activeBranch!),
           parentComponent,
           null, // fallback tree will not have suspense context
           isSVG,

+ 66 - 0
packages/vue/__tests__/e2e/Transition.spec.ts

@@ -1586,6 +1586,72 @@ describe('e2e: Transition', () => {
       expect(barMountSpy).toBeCalledTimes(1)
       expect(barMountSpy).toHaveBeenNthCalledWith(1, true, false, true)
     })
+
+    // #8105
+    test(
+      'trigger again when transition is not finished',
+      async () => {
+        await page().evaluate(duration => {
+          const { createApp, shallowRef, h } = (window as any).Vue
+          const One = {
+            async setup() {
+              return () => h('div', { class: 'test' }, 'one')
+            }
+          }
+          const Two = {
+            async setup() {
+              return () => h('div', { class: 'test' }, 'two')
+            }
+          }
+          createApp({
+            template: `
+            <div id="container">
+              <transition name="test" mode="out-in" duration="${duration}">
+                <Suspense>
+                  <component :is="view"/>
+                </Suspense>
+              </transition>
+            </div>
+            <button id="toggleBtn" @click="click">button</button>
+          `,
+            setup: () => {
+              const view = shallowRef(One)
+              const click = () => {
+                view.value = view.value === One ? Two : One
+              }
+              return { view, click }
+            }
+          }).mount('#app')
+        }, duration)
+
+        await nextFrame()
+        expect(await html('#container')).toBe(
+          '<div class="test test-enter-active test-enter-to">one</div>'
+        )
+
+        await transitionFinish()
+        expect(await html('#container')).toBe('<div class="test">one</div>')
+
+        // trigger twice
+        classWhenTransitionStart()
+        classWhenTransitionStart()
+        await nextFrame()
+        expect(await html('#container')).toBe(
+          '<div class="test test-leave-active test-leave-to">one</div>'
+        )
+
+        await transitionFinish()
+        await nextFrame()
+        expect(await html('#container')).toBe(
+          '<div class="test test-enter-active test-enter-to">one</div>'
+        )
+
+        await transitionFinish()
+        await nextFrame()
+        expect(await html('#container')).toBe('<div class="test">one</div>')
+      },
+      E2E_TIMEOUT
+    )
   })
 
   describe('transition with v-show', () => {