]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: save
authordaiwei <daiwei521@126.com>
Tue, 28 Oct 2025 09:26:56 +0000 (17:26 +0800)
committerdaiwei <daiwei521@126.com>
Tue, 28 Oct 2025 09:26:56 +0000 (17:26 +0800)
packages/runtime-dom/src/apiCustomElement.ts
packages/runtime-vapor/__tests__/customElement.spec.ts

index 341ed48e3df7a91b69a2a2ee32a15fb59ea69079..1a67726de0333740c983201a653276643920b0e1 100644 (file)
@@ -632,11 +632,15 @@ export abstract class VueElementBase<
   protected _renderSlots(): void {
     const outlets = this._getSlots()
     const scopeId = this._instance!.type.__scopeId
+    const slotReplacements: Map<Node, Node[]> = new Map()
+
     for (let i = 0; i < outlets.length; i++) {
       const o = outlets[i] as HTMLSlotElement
       const slotName = o.getAttribute('name') || 'default'
       const content = this._slots![slotName]
       const parent = o.parentNode!
+      const replacementNodes: Node[] = []
+
       if (content) {
         for (const n of content) {
           // for :slotted css
@@ -650,11 +654,66 @@ export abstract class VueElementBase<
             }
           }
           parent.insertBefore(n, o)
+          replacementNodes.push(n)
+        }
+      } else {
+        while (o.firstChild) {
+          const child = o.firstChild
+          parent.insertBefore(child, o)
+          replacementNodes.push(child)
+        }
+      }
+
+      slotReplacements.set(o, replacementNodes)
+    }
+
+    // For Vapor: update fragment nodes before removing slots from DOM
+    if (slotReplacements.size > 0 && this._instance && this._instance.vapor) {
+      // @ts-expect-error TODO refactor
+      this._replaceNodesInFragments(this._instance.block, slotReplacements)
+    }
+
+    // Now safe to remove slots from DOM
+    slotReplacements.forEach((_, o) => o.parentNode!.removeChild(o))
+  }
+
+  /**
+   * Replace slot nodes with their content in fragment nodes arrays
+   * @internal
+   */
+  private _replaceNodesInFragments(
+    block: any,
+    replacements: Map<Node, Node[]>,
+  ): void {
+    if (!block) return
+
+    if (Array.isArray(block)) {
+      for (let i = 0; i < block.length; i++) {
+        this._replaceNodesInFragments(block[i], replacements)
+      }
+    } else if (block.nodes !== undefined) {
+      // This is a fragment with nodes property
+      if (Array.isArray(block.nodes)) {
+        // Replace slot nodes with their content
+        const newNodes: any[] = []
+        for (const node of block.nodes) {
+          if (node instanceof Node && replacements.has(node)) {
+            // Replace with the content nodes
+            newNodes.push(...replacements.get(node)!)
+          } else {
+            newNodes.push(node)
+            // Recursively process nested fragments
+            this._replaceNodesInFragments(node, replacements)
+          }
         }
+        block.nodes = newNodes
+      } else if (block.nodes instanceof Node && replacements.has(block.nodes)) {
+        // Replace single node with its content
+        const replacement = replacements.get(block.nodes)!
+        block.nodes = replacement.length === 1 ? replacement[0] : replacement
       } else {
-        while (o.firstChild) parent.insertBefore(o.firstChild, o)
+        this._replaceNodesInFragments(block.nodes, replacements)
       }
-      parent.removeChild(o)
     }
   }
 
index 894d4976391f90bc38be586b28c96e6110cc0bed..3f0f35fa36b3a5830dd4e4603011fe6116843ad8 100644 (file)
@@ -1344,7 +1344,7 @@ describe('defineVaporCustomElement', () => {
     )
     customElements.define('my-el-shadowroot-false-slots', ES)
 
-    test.todo('should render slots', async () => {
+    test('should render slots', async () => {
       container.innerHTML =
         `<my-el-shadowroot-false-slots>` +
         `<span>default</span>text` +
@@ -1362,7 +1362,9 @@ describe('defineVaporCustomElement', () => {
       toggle.value = false
       await nextTick()
       expect(e.innerHTML).toBe(
-        `<span>default</span>text` + `<!--if-->` + `<div>fallback</div>`,
+        `<span>default</span>text<!--slot-->` +
+          `<!--if-->` +
+          `<div>fallback</div><!--slot-->`,
       )
     })