Преглед изворни кода

fix(runtime-vapor): update interop slot patch target after moves

daiwei пре 1 месец
родитељ
комит
ba9cd6ee77

+ 63 - 0
packages/runtime-vapor/__tests__/vdomInterop.spec.ts

@@ -29,6 +29,7 @@ import {
 import { makeInteropRender } from './_utils'
 import {
   VaporKeepAlive,
+  VaporTeleport,
   applyTextModel,
   applyVShow,
   child,
@@ -2392,6 +2393,68 @@ describe('vdomInterop', () => {
         target.remove()
       }
     })
+
+    test('should patch vdom slot content in the new teleport target after move', async () => {
+      const targetA = document.createElement('div')
+      targetA.id = 'interop-slot-target-a'
+      const targetB = document.createElement('div')
+      targetB.id = 'interop-slot-target-b'
+      document.body.append(targetA, targetB)
+
+      const to = ref('#interop-slot-target-a')
+      const useAltRoot = ref(false)
+
+      try {
+        const VaporChild = defineVaporComponent({
+          setup() {
+            return createComponent(
+              VaporTeleport,
+              {
+                to: () => to.value,
+              },
+              {
+                default: () => createSlot('default'),
+              },
+            )
+          },
+        })
+
+        const App = defineComponent({
+          setup() {
+            return () =>
+              h(VaporChild as any, null, {
+                default: () => [
+                  useAltRoot.value ? h('p', 'moved') : h('div', 'initial'),
+                ],
+              })
+          },
+        })
+
+        const host = document.createElement('div')
+        const app = createApp(App)
+        app.use(vaporInteropPlugin)
+        app.mount(host)
+        await nextTick()
+
+        expect(targetA.innerHTML).toBe('<div>initial</div>')
+        expect(targetB.innerHTML).toBe('')
+
+        to.value = '#interop-slot-target-b'
+        await nextTick()
+
+        expect(targetA.innerHTML).toBe('')
+        expect(targetB.innerHTML).toBe('<div>initial</div>')
+
+        useAltRoot.value = true
+        await nextTick()
+
+        expect(targetA.innerHTML).toBe('')
+        expect(targetB.innerHTML).toBe('<p>moved</p>')
+      } finally {
+        targetA.remove()
+        targetB.remove()
+      }
+    })
   })
 
   describe('Suspense', () => {

+ 12 - 8
packages/runtime-vapor/src/vdomInterop.ts

@@ -955,12 +955,16 @@ function renderVDOMSlot(
   let isMounted = false
   let currentBlock: Block | null = null
   let currentVNode: VNode | null = null
+  let currentParentNode: ParentNode | undefined
+  let currentAnchor: Node | null | undefined
 
   frag.insert = (parentNode, anchor) => {
     if (isHydrating) return
+    currentParentNode = parentNode
+    currentAnchor = anchor
 
     if (!isMounted) {
-      render(parentNode, anchor)
+      render()
       isMounted = true
     } else {
       if (currentVNode) {
@@ -989,7 +993,7 @@ function renderVDOMSlot(
     if (isMounted && frag.onUpdated) frag.onUpdated.forEach(m => m())
   }
 
-  const render = (parentNode?: ParentNode, anchor?: Node | null) => {
+  const render = () => {
     const prev = currentInstance
     simpleSetCurrentInstance(instance)
     try {
@@ -1068,14 +1072,14 @@ function renderVDOMSlot(
             frag.$key = getVNodeKey(resolved)
             trackSlotVNodeUpdates(frag, resolved)
             if (currentBlock) {
-              remove(currentBlock, parentNode)
+              remove(currentBlock, currentParentNode)
               currentBlock = null
             }
             internals.p(
               currentVNode,
               resolved,
-              parentNode!,
-              anchor,
+              currentParentNode!,
+              currentAnchor,
               parentComponent as any,
               suspense,
               undefined, // namespace
@@ -1094,16 +1098,16 @@ function renderVDOMSlot(
               currentVNode = null
             }
             if (currentBlock) {
-              remove(currentBlock, parentNode)
+              remove(currentBlock, currentParentNode)
             }
-            insert(resolved, parentNode!, anchor)
+            insert(resolved, currentParentNode!, currentAnchor)
             currentBlock = resolved
             frag.nodes = resolved as any
             return
           }
 
           if (currentBlock) {
-            remove(currentBlock, parentNode)
+            remove(currentBlock, currentParentNode)
             currentBlock = null
           }
           if (currentVNode) {