name: \\"foo\\",
fn: _withCtx(() => [
_createElementVNode(\\"div\\")
- ])
+ ]),
+ key: \\"0\\"
}
: undefined,
_renderList(_ctx.list, (i) => {
(_ctx.ok)
? {
name: \\"one\\",
- fn: _withCtx((props) => [_toDisplayString(props)])
+ fn: _withCtx((props) => [_toDisplayString(props)]),
+ key: \\"0\\"
}
: undefined
]), 1024 /* DYNAMIC_SLOTS */))
ok
? {
name: \\"one\\",
- fn: _withCtx(() => [\\"foo\\"])
+ fn: _withCtx(() => [\\"foo\\"]),
+ key: \\"0\\"
}
: orNot
? {
name: \\"two\\",
- fn: _withCtx((props) => [\\"bar\\"])
+ fn: _withCtx((props) => [\\"bar\\"]),
+ key: \\"1\\"
}
: {
name: \\"one\\",
- fn: _withCtx(() => [\\"baz\\"])
+ fn: _withCtx(() => [\\"baz\\"]),
+ key: \\"2\\"
}
]), 1024 /* DYNAMIC_SLOTS */))
}
ok
? {
name: \\"one\\",
- fn: _withCtx(() => [\\"hello\\"])
+ fn: _withCtx(() => [\\"hello\\"]),
+ key: \\"0\\"
}
: undefined
]), 1024 /* DYNAMIC_SLOTS */))
fn: {
type: NodeTypes.JS_FUNCTION_EXPRESSION,
returns: [{ type: NodeTypes.TEXT, content: `hello` }]
- }
+ },
+ key: `0`
}),
alternate: {
content: `undefined`,
content: { content: `props` }
}
]
- }
+ },
+ key: `0`
}),
alternate: {
content: `undefined`,
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: undefined,
returns: [{ type: NodeTypes.TEXT, content: `foo` }]
- }
+ },
+ key: `0`
}),
alternate: {
type: NodeTypes.JS_CONDITIONAL_EXPRESSION,
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: { content: `props` },
returns: [{ type: NodeTypes.TEXT, content: `bar` }]
- }
+ },
+ key: `1`
}),
alternate: createObjectMatcher({
name: `one`,
type: NodeTypes.JS_FUNCTION_EXPRESSION,
params: undefined,
returns: [{ type: NodeTypes.TEXT, content: `baz` }]
- }
+ },
+ key: `2`
})
}
}
let hasNamedDefaultSlot = false
const implicitDefaultChildren: TemplateChildNode[] = []
const seenSlotNames = new Set<string>()
+ let conditionalBranchIndex = 0
for (let i = 0; i < children.length; i++) {
const slotElement = children[i]
dynamicSlots.push(
createConditionalExpression(
vIf.exp!,
- buildDynamicSlot(slotName, slotFunction),
+ buildDynamicSlot(slotName, slotFunction, conditionalBranchIndex++),
defaultFallback
)
)
conditional.alternate = vElse.exp
? createConditionalExpression(
vElse.exp,
- buildDynamicSlot(slotName, slotFunction),
+ buildDynamicSlot(
+ slotName,
+ slotFunction,
+ conditionalBranchIndex++
+ ),
defaultFallback
)
- : buildDynamicSlot(slotName, slotFunction)
+ : buildDynamicSlot(slotName, slotFunction, conditionalBranchIndex++)
} else {
context.onError(
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, vElse.loc)
function buildDynamicSlot(
name: ExpressionNode,
- fn: FunctionExpression
+ fn: FunctionExpression,
+ index?: number
): ObjectExpression {
- return createObjectExpression([
+ const props = [
createObjectProperty(`name`, name),
createObjectProperty(`fn`, fn)
- ])
+ ]
+ if (index != null) {
+ props.push(
+ createObjectProperty(`key`, createSimpleExpression(String(index), true))
+ )
+ }
+ return createObjectExpression(props)
}
function hasForwardedSlots(children: TemplateChildNode[]): boolean {
_createTextVNode(\\"foo\\")
]
}
- })
+ }),
+ key: \\"0\\"
}
: undefined
]), _parent))
expect(actual).toEqual({ descriptor: slot })
})
+ it('should attach key', () => {
+ const dynamicSlot = [{ name: 'descriptor', fn: slot, key: '1' }]
+
+ const actual = createSlots(record, dynamicSlot)
+ const ret = actual.descriptor()
+ // @ts-ignore
+ expect(ret.key).toBe('1')
+ })
+
it('should add all slots to the record', () => {
const dynamicSlot = [
{ name: 'descriptor', fn: slot },
interface CompiledSlotDescriptor {
name: string
fn: Slot
+ key?: string
}
/**
}
} else if (slot) {
// conditional single slot generated by <template v-if="..." #foo>
- slots[slot.name] = slot.fn
+ slots[slot.name] = slot.key
+ ? (...args: any[]) => {
+ const res = slot.fn(...args)
+ // attach branch key so each conditional branch is considered a
+ // different fragment
+ ;(res as any).key = slot.key
+ return res
+ }
+ : slot.fn
}
}
return slots
const validSlotContent = slot && ensureValidVNode(slot(props))
const rendered = createBlock(
Fragment,
- { key: props.key || `_${name}` },
+ {
+ key:
+ props.key ||
+ // slot content array of a dynamic conditional slot may have a branch
+ // key attached in the `createSlots` helper, respect that
+ (validSlotContent && (validSlotContent as any).key) ||
+ `_${name}`
+ },
validSlotContent || (fallback ? fallback() : []),
validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE
? PatchFlags.STABLE_FRAGMENT