From: edison Date: Wed, 5 Nov 2025 09:04:33 +0000 (+0800) Subject: fix(custom-element): optimize slot retrieval to avoid duplicates (#13961) X-Git-Tag: v3.5.23~11 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=84ca349fef73f6f55fc98299fcfa5c1eeef721db;p=thirdparty%2Fvuejs%2Fcore.git fix(custom-element): optimize slot retrieval to avoid duplicates (#13961) close #13955 --- diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index 04953f8251..1225326abc 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -1614,6 +1614,44 @@ describe('defineCustomElement', () => { app.unmount() }) + test('teleport target is ancestor of custom element host', async () => { + const Child = defineCustomElement( + { + render() { + return [ + h(Teleport, { to: '#t1' }, [renderSlot(this.$slots, 'header')]), + ] + }, + }, + { shadowRoot: false }, + ) + customElements.define('my-el-teleport-child-target', Child) + + const App = { + render() { + return h('div', { id: 't1' }, [ + h('my-el-teleport-child-target', null, { + default: () => [h('div', { slot: 'header' }, 'header')], + }), + ]) + }, + } + const app = createApp(App) + app.mount(container) + + const target1 = document.getElementById('t1')! + expect(target1.outerHTML).toBe( + `
` + + `` + + `` + + `` + + `
header
` + + `
`, + ) + + app.unmount() + }) + test('toggle nested custom element with shadowRoot: false', async () => { customElements.define( 'my-el-child-shadow-false', diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index a8f64210c3..85d37bc117 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -688,11 +688,18 @@ export class VueElement if (this._teleportTargets) { roots.push(...this._teleportTargets) } - return roots.reduce((res, i) => { - res.push(...Array.from(i.querySelectorAll('slot'))) - return res - }, []) + + const slots = new Set() + for (const root of roots) { + const found = root.querySelectorAll('slot') + for (let i = 0; i < found.length; i++) { + slots.add(found[i]) + } + } + + return Array.from(slots) } + /** * @internal */