Prechádzať zdrojové kódy

fix(runtime-vapor): apply transition hooks to slot fallbacks (#14853)

close #14851
edison 4 týždňov pred
rodič
commit
a42a8a2c4d

+ 46 - 0
packages/runtime-vapor/__tests__/components/Transition.spec.ts

@@ -409,6 +409,52 @@ describe('Transition', () => {
     expect(host.innerHTML).not.toContain('<div>fallback</div>')
   })
 
+  test('slot fallback should trigger enter hooks when slot content becomes empty', async () => {
+    const onBeforeEnter = vi.fn()
+    const onEnter = vi.fn()
+    const data = ref({
+      show: true,
+      onBeforeEnter,
+      onEnter,
+    })
+    const Child = compile(
+      `<template>
+        <Transition
+          @before-enter="data.onBeforeEnter"
+          @enter="data.onEnter"
+        >
+          <slot>
+            <div>22</div>
+          </slot>
+        </Transition>
+      </template>`,
+      data,
+    )
+    const App = compile(
+      `<template>
+        <button @click="data.show = !data.show">Toggle</button>
+        <components.Child>
+          <div v-if="data.show">3</div>
+        </components.Child>
+      </template>`,
+      data,
+      { Child },
+    )
+    const { host } = define(App as any).render()
+
+    host.querySelector('button')!.click()
+    await nextTick()
+
+    expect(host.innerHTML).toContain(
+      '<div class="v-leave-from v-leave-active">3</div>',
+    )
+    expect(host.innerHTML).toContain(
+      '<div class="v-enter-from v-enter-active">22</div>',
+    )
+    expect(onBeforeEnter).toHaveBeenCalledTimes(1)
+    expect(onEnter).toHaveBeenCalledTimes(1)
+  })
+
   test('dynamic default slot source should trigger enter hooks when toggled on', async () => {
     const onBeforeEnter = vi.fn()
     const onEnter = vi.fn()

+ 12 - 0
packages/runtime-vapor/src/fragment.ts

@@ -1130,6 +1130,18 @@ function commitSlotFallback(
   outlet.activeFallback = block
   outlet.fallbackScope = scope
   ensureSlotFallbackOrderHook(outlet, block)
+  if (isTransitionEnabled) {
+    const transitionOutlet = outlet as SlotFallbackOutlet & TransitionOptions
+    if (transitionOutlet.$transition) {
+      // Match VDOM slot fallback branch identity so fallback enter does not
+      // early-remove the currently leaving slot content.
+      setBlockKey(block, '_fb')
+      transitionOutlet.$transition = applyTransitionHooks(
+        block,
+        transitionOutlet.$transition,
+      )
+    }
+  }
   insertActiveSlotFallback(outlet)
 }