]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: handling slot update
authordaiwei <daiwei521@126.com>
Tue, 28 Oct 2025 13:24:20 +0000 (21:24 +0800)
committerdaiwei <daiwei521@126.com>
Tue, 28 Oct 2025 13:24:20 +0000 (21:24 +0800)
packages/runtime-dom/src/apiCustomElement.ts
packages/runtime-vapor/src/apiDefineVaporCustomElement.ts

index 1a67726de0333740c983201a653276643920b0e1..12cb859abce22d0ea78f5775f3ce9f783c39a70c 100644 (file)
@@ -255,6 +255,7 @@ export abstract class VueElementBase<
   protected abstract _mount(def: Def): void
   protected abstract _update(): void
   protected abstract _unmount(): void
+  protected abstract _updateSlotNodes(slot: Map<Node, Node[]>): void
 
   constructor(
     /**
@@ -663,58 +664,11 @@ export abstract class VueElementBase<
           replacementNodes.push(child)
         }
       }
-
+      parent.removeChild(o)
       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 {
-        this._replaceNodesInFragments(block.nodes, replacements)
-      }
-    }
+    this._updateSlotNodes(slotReplacements)
   }
 
   /**
@@ -814,6 +768,13 @@ export class VueElement extends VueElementBase<
     this._app = this._instance = null
   }
 
+  /**
+   * Only called when shadowRoot is false
+   */
+  protected _updateSlotNodes(replacements: Map<Node, Node[]>): void {
+    // do nothing
+  }
+
   private _createVNode(): VNode<any, any> {
     const baseProps: VNodeProps = {}
     if (!this.shadowRoot) {
index 6cf9b5f67aa84c870a60b98193a4ffffce41abfe..4f01a50ed48ebf37e5a94ff55113987713915ad0 100644 (file)
@@ -1,5 +1,10 @@
 import { extend, isPlainObject } from '@vue/shared'
-import { createComponent, createVaporApp, defineVaporComponent } from '.'
+import {
+  createComponent,
+  createVaporApp,
+  defineVaporComponent,
+  isFragment,
+} from '.'
 import {
   type CreateAppFunction,
   type CustomElementOptions,
@@ -11,6 +16,7 @@ import type {
   VaporComponent,
   VaporComponentInstance,
 } from './component'
+import type { Block } from './block'
 
 export type VaporElementConstructor<P = {}> = {
   new (initialProps?: Record<string, any>): VaporElement & P
@@ -124,6 +130,49 @@ export class VaporElement extends VueElementBase<
     this._app = this._instance = null
   }
 
+  /**
+   * Only called when shadowRoot is false
+   */
+  protected _updateSlotNodes(replacements: Map<Node, Node[]>): void {
+    this._updateFragmentNodes(
+      (this._instance! as VaporComponentInstance).block,
+      replacements,
+    )
+  }
+
+  /**
+   * Replace slot nodes with their replace content
+   * @internal
+   */
+  private _updateFragmentNodes(
+    block: Block,
+    replacements: Map<Node, Node[]>,
+  ): void {
+    if (Array.isArray(block)) {
+      block.forEach(item => this._updateFragmentNodes(item, replacements))
+      return
+    }
+
+    if (!isFragment(block)) return
+    const { nodes } = block
+    if (Array.isArray(nodes)) {
+      const newNodes: Block[] = []
+      for (const node of nodes) {
+        if (node instanceof HTMLSlotElement) {
+          newNodes.push(...replacements.get(node)!)
+        } else {
+          this._updateFragmentNodes(node, replacements)
+          newNodes.push(node)
+        }
+      }
+      block.nodes = newNodes
+    } else if (nodes instanceof HTMLSlotElement) {
+      block.nodes = replacements.get(nodes)!
+    } else {
+      this._updateFragmentNodes(nodes, replacements)
+    }
+  }
+
   private _createComponent() {
     this._def.ce = instance => {
       this._app!._ceComponent = this._instance = instance