fix(components): [onlyChild] no warning when there are multiple child (#21958)

This commit is contained in:
qiang
2025-08-30 12:25:02 +08:00
committed by GitHub
parent a6d319bfaa
commit 0aa72d510b
2 changed files with 23 additions and 13 deletions

View File

@@ -119,7 +119,7 @@ describe('ElOnlyChild', () => {
await nextTick()
expect(debugWarn).toHaveBeenCalledTimes(1)
expect(wrapper.text()).toBe('')
expect(wrapper.text()).toBe(AXIOM)
})
it('should render nothing when no children provided', async () => {
@@ -129,4 +129,12 @@ describe('ElOnlyChild', () => {
expect(debugWarn).not.toHaveBeenCalled()
expect(wrapper.text()).toBe('')
})
it('should warns about having multiple children', async () => {
wrapper = createComponent(() => [h(Fragment, null, [AXIOM, AXIOM])])
await nextTick()
expect(debugWarn).toHaveBeenCalledTimes(1)
expect(wrapper.text()).toBe(AXIOM)
})
})

View File

@@ -28,17 +28,15 @@ export const OnlyChild = defineComponent({
return () => {
const defaultSlot = slots.default?.(attrs)
if (!defaultSlot) return null
const [firstLegitNode, length] = findFirstLegitChild(defaultSlot)
if (defaultSlot.length > 1) {
debugWarn(NAME, 'requires exact only one valid child.')
return null
}
const firstLegitNode = findFirstLegitChild(defaultSlot)
if (!firstLegitNode) {
debugWarn(NAME, 'no valid child node found')
return null
}
if (length > 1) {
debugWarn(NAME, 'requires exact only one valid child.')
}
return withDirectives(cloneVNode(firstLegitNode!, attrs), [
[forwardRefDirective],
@@ -47,9 +45,13 @@ export const OnlyChild = defineComponent({
},
})
function findFirstLegitChild(node: VNode[] | undefined): VNode | null {
if (!node) return null
function findFirstLegitChild(
node: VNode[] | undefined
): [VNode | null, number] {
if (!node) return [null, 0]
const children = node as VNode[]
const len = children.filter((c) => c.type !== Comment).length
for (const child of children) {
/**
* when user uses h(Fragment, [text]) to render plain string,
@@ -62,16 +64,16 @@ function findFirstLegitChild(node: VNode[] | undefined): VNode | null {
continue
case Text:
case 'svg':
return wrapTextContent(child)
return [wrapTextContent(child), len]
case Fragment:
return findFirstLegitChild(child.children as VNode[])
default:
return child
return [child, len]
}
}
return wrapTextContent(child)
return [wrapTextContent(child), len]
}
return null
return [null, 0]
}
function wrapTextContent(s: string | VNode) {