fix(compiler/v-slot): handle implicit default slot mixed with named slots

This commit is contained in:
Evan You
2020-01-06 15:31:21 -05:00
parent bb6a346996
commit 2ac4b723e0
4 changed files with 110 additions and 40 deletions

View File

@@ -117,9 +117,9 @@ export function buildSlots(
// 1. Check for default slot with slotProps on component itself.
// <Comp v-slot="{ prop }"/>
const explicitDefaultSlot = findDir(node, 'slot', true)
if (explicitDefaultSlot) {
const { arg, exp, loc } = explicitDefaultSlot
const onComponentDefaultSlot = findDir(node, 'slot', true)
if (onComponentDefaultSlot) {
const { arg, exp, loc } = onComponentDefaultSlot
if (arg) {
context.onError(
createCompilerError(ErrorCodes.X_V_SLOT_NAMED_SLOT_ON_COMPONENT, loc)
@@ -131,8 +131,10 @@ export function buildSlots(
// 2. Iterate through children and check for template slots
// <template v-slot:foo="{ prop }">
let hasTemplateSlots = false
let extraneousChild: TemplateChildNode | undefined = undefined
let hasNamedDefaultSlot = false
const implicitDefaultChildren: TemplateChildNode[] = []
const seenSlotNames = new Set<string>()
for (let i = 0; i < children.length; i++) {
const slotElement = children[i]
let slotDir
@@ -142,13 +144,13 @@ export function buildSlots(
!(slotDir = findDir(slotElement, 'slot', true))
) {
// not a <template v-slot>, skip.
if (slotElement.type !== NodeTypes.COMMENT && !extraneousChild) {
extraneousChild = slotElement
if (slotElement.type !== NodeTypes.COMMENT) {
implicitDefaultChildren.push(slotElement)
}
continue
}
if (explicitDefaultSlot) {
if (onComponentDefaultSlot) {
// already has on-component default slot - this is incorrect usage.
context.onError(
createCompilerError(ErrorCodes.X_V_SLOT_MIXED_SLOT_USAGE, slotDir.loc)
@@ -267,23 +269,33 @@ export function buildSlots(
continue
}
seenSlotNames.add(staticSlotName)
if (staticSlotName === 'default') {
hasNamedDefaultSlot = true
}
}
slotsProperties.push(createObjectProperty(slotName, slotFunction))
}
}
if (hasTemplateSlots && extraneousChild) {
context.onError(
createCompilerError(
ErrorCodes.X_V_SLOT_EXTRANEOUS_NON_SLOT_CHILDREN,
extraneousChild.loc
)
)
}
if (!explicitDefaultSlot && !hasTemplateSlots) {
// implicit default slot.
slotsProperties.push(buildDefaultSlot(undefined, children, loc))
if (!onComponentDefaultSlot) {
if (!hasTemplateSlots) {
// implicit default slot (on component)
slotsProperties.push(buildDefaultSlot(undefined, children, loc))
} else if (implicitDefaultChildren.length) {
// implicit default slot (mixed with named slots)
if (hasNamedDefaultSlot) {
context.onError(
createCompilerError(
ErrorCodes.X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN,
implicitDefaultChildren[0].loc
)
)
} else {
slotsProperties.push(
buildDefaultSlot(undefined, implicitDefaultChildren, loc)
)
}
}
}
let slots: ObjectExpression | CallExpression = createObjectExpression(