From: daiwei Date: Tue, 28 Oct 2025 13:24:20 +0000 (+0800) Subject: refactor: handling slot update X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cbf18fb848ca286a783c4a5c56605f4a05e3641c;p=thirdparty%2Fvuejs%2Fcore.git refactor: handling slot update --- diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index 1a67726de0..12cb859abc 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -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): 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, - ): 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): void { + // do nothing + } + private _createVNode(): VNode { const baseProps: VNodeProps = {} if (!this.shadowRoot) { diff --git a/packages/runtime-vapor/src/apiDefineVaporCustomElement.ts b/packages/runtime-vapor/src/apiDefineVaporCustomElement.ts index 6cf9b5f67a..4f01a50ed4 100644 --- a/packages/runtime-vapor/src/apiDefineVaporCustomElement.ts +++ b/packages/runtime-vapor/src/apiDefineVaporCustomElement.ts @@ -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

= { new (initialProps?: Record): 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): void { + this._updateFragmentNodes( + (this._instance! as VaporComponentInstance).block, + replacements, + ) + } + + /** + * Replace slot nodes with their replace content + * @internal + */ + private _updateFragmentNodes( + block: Block, + replacements: Map, + ): 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