Browse Source

fix(runtime-vapor): handle transition in-out leave without incoming branch

daiwei 1 tháng trước cách đây
mục cha
commit
8caa9d1902

+ 92 - 0
packages-private/vapor-e2e-test/__tests__/transition.spec.ts

@@ -1789,6 +1789,98 @@ describe('vapor transition', () => {
   })
 
   describe('mode', () => {
+    test(
+      'in-out mode with v-if',
+      async () => {
+        const btnSelector = '.in-out-if > button'
+        const containerSelector = '.in-out-if > div'
+        const childSelector = `${containerSelector} > div`
+
+        expect(await html(containerSelector)).toBe(`<div>text1</div>`)
+
+        expect(
+          (await transitionStart(btnSelector, childSelector)).outerHTML,
+        ).toBe(`<div class="v-leave-from v-leave-active">text1</div>`)
+
+        await waitForInnerHTML(
+          containerSelector,
+          `<div class="v-leave-active v-leave-to">text1</div>`,
+        )
+
+        await waitForInnerHTML(containerSelector, ``)
+
+        expect(
+          (await transitionStart(btnSelector, childSelector)).outerHTML,
+        ).toBe(`<div class="v-enter-from v-enter-active">text1</div>`)
+
+        await waitForInnerHTML(
+          containerSelector,
+          `<div class="v-enter-active v-enter-to">text1</div>`,
+        )
+
+        await waitForInnerHTML(containerSelector, `<div class="">text1</div>`)
+      },
+      E2E_TIMEOUT,
+    )
+
+    test(
+      'out-in mode with if/else-if',
+      async () => {
+        const btnSelector = '.out-in-if-else-if > button'
+        const containerSelector = '.out-in-if-else-if > div'
+        const childSelector = `${containerSelector} > div`
+
+        expect(await html(containerSelector)).toBe(`<div>text2</div>`)
+
+        await click(btnSelector)
+        await nextTick()
+        expect(await html(containerSelector)).toBe(`<div>text2</div>`)
+
+        expect(
+          (await transitionStart(btnSelector, childSelector)).outerHTML,
+        ).toBe(`<div class="v-leave-from v-leave-active">text2</div>`)
+
+        await waitForInnerHTML(
+          containerSelector,
+          `<div class="v-leave-active v-leave-to">text2</div>`,
+        )
+
+        await waitForInnerHTML(
+          containerSelector,
+          `<div class="v-enter-from v-enter-active">text1</div>`,
+        )
+
+        await waitForInnerHTML(
+          containerSelector,
+          `<div class="v-enter-active v-enter-to">text1</div>`,
+        )
+
+        await waitForInnerHTML(containerSelector, `<div class="">text1</div>`)
+
+        expect(
+          (await transitionStart(btnSelector, childSelector)).outerHTML,
+        ).toBe(`<div class="v-leave-from v-leave-active">text1</div>`)
+
+        await waitForInnerHTML(
+          containerSelector,
+          `<div class="v-leave-active v-leave-to">text1</div>`,
+        )
+
+        await waitForInnerHTML(
+          containerSelector,
+          `<div class="v-enter-from v-enter-active">text2</div>`,
+        )
+
+        await waitForInnerHTML(
+          containerSelector,
+          `<div class="v-enter-active v-enter-to">text2</div>`,
+        )
+
+        await waitForInnerHTML(containerSelector, `<div class="">text2</div>`)
+      },
+      E2E_TIMEOUT,
+    )
+
     test(
       'should work with out-in mode',
       async () => {

+ 20 - 0
packages-private/vapor-e2e-test/transition/cases/mode/in-out-mode-with-v-if.vue

@@ -0,0 +1,20 @@
+<script setup vapor>
+import { ref } from 'vue'
+
+const n = ref(1)
+
+function addN() {
+  n.value = (n.value + 1) % 2
+}
+</script>
+
+<template>
+  <div class="in-out-if">
+    <button @click="addN">addN</button>
+    <div>
+      <Transition mode="in-out">
+        <div v-if="n">text1</div>
+      </Transition>
+    </div>
+  </div>
+</template>

+ 21 - 0
packages-private/vapor-e2e-test/transition/cases/mode/out-in-mode-with-if-else-if.vue

@@ -0,0 +1,21 @@
+<script setup vapor>
+import { ref } from 'vue'
+
+const n = ref(1)
+
+function addN() {
+  n.value = (n.value + 1) % 3
+}
+</script>
+
+<template>
+  <div class="out-in-if-else-if">
+    <button @click="addN">addN</button>
+    <div>
+      <Transition mode="out-in">
+        <div v-if="!n">text1</div>
+        <div v-else-if="n">text2</div>
+      </Transition>
+    </div>
+  </div>
+</template>

+ 7 - 1
packages/runtime-vapor/src/fragment.ts

@@ -149,7 +149,13 @@ export class DynamicFragment extends VaporFragment {
         this.scope.stop()
       }
       const mode = transition && transition.mode
-      if (mode) {
+
+      if (
+        mode &&
+        // in-out only works when there is an incoming branch to trigger
+        // delayedLeave; otherwise the current branch should leave immediately.
+        (mode !== 'in-out' || (mode === 'in-out' && render))
+      ) {
         applyTransitionLeaveHooks(this.nodes, transition, () => {
           const pending = this.pending
           if (pending) {