fix(custom-element): use PatchFlags.BAIL for slot when props are present (#13907)

close #13904
This commit is contained in:
edison 2025-09-24 17:08:25 +08:00 committed by GitHub
parent 836b82976f
commit 5358bca4a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 1 deletions

View File

@ -37,6 +37,7 @@ export function renderSlot(
isAsyncWrapper(currentRenderingInstance!.parent) && isAsyncWrapper(currentRenderingInstance!.parent) &&
currentRenderingInstance!.parent.ce) currentRenderingInstance!.parent.ce)
) { ) {
const hasProps = Object.keys(props).length > 0
// in custom element mode, render <slot/> as actual slot outlets // in custom element mode, render <slot/> as actual slot outlets
// wrap it with a fragment because in shadowRoot: false mode the slot // wrap it with a fragment because in shadowRoot: false mode the slot
// element gets replaced by injected content // element gets replaced by injected content
@ -47,7 +48,7 @@ export function renderSlot(
Fragment, Fragment,
null, null,
[createVNode('slot', props, fallback && fallback())], [createVNode('slot', props, fallback && fallback())],
PatchFlags.STABLE_FRAGMENT, hasProps ? PatchFlags.BAIL : PatchFlags.STABLE_FRAGMENT,
) )
) )
} }

View File

@ -638,6 +638,33 @@ describe('defineCustomElement', () => {
`<div><slot><div>fallback</div></slot></div><div><slot name="named"></slot></div>`, `<div><slot><div>fallback</div></slot></div><div><slot name="named"></slot></div>`,
) )
}) })
test('render slot props', async () => {
const foo = ref('foo')
const E = defineCustomElement({
render() {
return [
h(
'div',
null,
renderSlot(this.$slots, 'default', { class: foo.value }),
),
]
},
})
customElements.define('my-el-slot-props', E)
container.innerHTML = `<my-el-slot-props><span>hi</span></my-el-slot-props>`
const e = container.childNodes[0] as VueElement
expect(e.shadowRoot!.innerHTML).toBe(
`<div><slot class="foo"></slot></div>`,
)
foo.value = 'bar'
await nextTick()
expect(e.shadowRoot!.innerHTML).toBe(
`<div><slot class="bar"></slot></div>`,
)
})
}) })
describe('provide/inject', () => { describe('provide/inject', () => {