2019-09-06 16:58:31 +00:00
|
|
|
import { ComponentInternalInstance, currentInstance } from './component'
|
2019-09-28 00:29:20 +00:00
|
|
|
import {
|
|
|
|
VNode,
|
|
|
|
NormalizedChildren,
|
|
|
|
normalizeVNode,
|
|
|
|
VNodeChild,
|
|
|
|
VNodeChildren
|
|
|
|
} from './vnode'
|
2019-06-03 11:58:12 +00:00
|
|
|
import { isArray, isFunction } from '@vue/shared'
|
2019-08-22 15:12:37 +00:00
|
|
|
import { ShapeFlags } from './shapeFlags'
|
2019-08-30 19:26:16 +00:00
|
|
|
import { warn } from './warning'
|
2019-05-31 10:07:43 +00:00
|
|
|
|
2019-09-28 00:29:20 +00:00
|
|
|
export type Slot = (...args: any[]) => VNodeChildren
|
2019-10-08 16:43:13 +00:00
|
|
|
|
|
|
|
export type InternalSlots = {
|
2019-05-31 10:07:43 +00:00
|
|
|
[name: string]: Slot
|
2019-10-08 16:43:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export type Slots = Readonly<InternalSlots>
|
|
|
|
|
2019-05-31 10:07:43 +00:00
|
|
|
export type RawSlots = {
|
|
|
|
[name: string]: unknown
|
2019-10-08 16:43:13 +00:00
|
|
|
_compiled?: boolean
|
2019-05-31 10:07:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const normalizeSlotValue = (value: unknown): VNode[] =>
|
|
|
|
isArray(value)
|
|
|
|
? value.map(normalizeVNode)
|
|
|
|
: [normalizeVNode(value as VNodeChild)]
|
|
|
|
|
2019-08-30 19:26:16 +00:00
|
|
|
const normalizeSlot = (key: string, rawSlot: Function): Slot => (
|
|
|
|
props: any
|
|
|
|
) => {
|
|
|
|
if (__DEV__ && currentInstance != null) {
|
|
|
|
warn(
|
|
|
|
`Slot "${key}" invoked outside of the render function: ` +
|
|
|
|
`this will not track dependencies used in the slot. ` +
|
|
|
|
`Invoke the slot function inside the render function instead.`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
return normalizeSlotValue(rawSlot(props))
|
|
|
|
}
|
2019-05-31 10:07:43 +00:00
|
|
|
|
|
|
|
export function resolveSlots(
|
2019-09-06 16:58:31 +00:00
|
|
|
instance: ComponentInternalInstance,
|
2019-05-31 10:07:43 +00:00
|
|
|
children: NormalizedChildren
|
|
|
|
) {
|
2019-10-08 16:43:13 +00:00
|
|
|
let slots: InternalSlots | void
|
2019-08-22 15:12:37 +00:00
|
|
|
if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
|
2019-10-08 16:43:13 +00:00
|
|
|
const rawSlots = children as RawSlots
|
|
|
|
if (rawSlots._compiled) {
|
2019-06-03 11:59:15 +00:00
|
|
|
// pre-normalized slots object generated by compiler
|
2019-05-31 10:07:43 +00:00
|
|
|
slots = children as Slots
|
|
|
|
} else {
|
|
|
|
slots = {}
|
2019-10-08 16:43:13 +00:00
|
|
|
for (const key in rawSlots) {
|
|
|
|
const value = rawSlots[key]
|
2019-05-31 10:07:43 +00:00
|
|
|
if (isFunction(value)) {
|
2019-10-08 16:43:13 +00:00
|
|
|
slots[key] = normalizeSlot(key, value)
|
2019-10-02 21:18:11 +00:00
|
|
|
} else if (value != null) {
|
2019-05-31 10:07:43 +00:00
|
|
|
if (__DEV__) {
|
2019-08-30 19:34:57 +00:00
|
|
|
warn(
|
|
|
|
`Non-function value encountered for slot "${key}". ` +
|
|
|
|
`Prefer function slots for better performance.`
|
|
|
|
)
|
2019-05-31 10:07:43 +00:00
|
|
|
}
|
2019-10-08 16:43:13 +00:00
|
|
|
const normalized = normalizeSlotValue(value)
|
|
|
|
slots[key] = () => normalized
|
2019-05-31 10:07:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-06-03 11:58:12 +00:00
|
|
|
} else if (children !== null) {
|
|
|
|
// non slot object children (direct value) passed to a component
|
2019-05-31 10:07:43 +00:00
|
|
|
if (__DEV__) {
|
2019-08-30 19:34:57 +00:00
|
|
|
warn(
|
|
|
|
`Non-function value encountered for default slot. ` +
|
|
|
|
`Prefer function slots for better performance.`
|
|
|
|
)
|
2019-05-31 10:07:43 +00:00
|
|
|
}
|
|
|
|
const normalized = normalizeSlotValue(children)
|
|
|
|
slots = { default: () => normalized }
|
|
|
|
}
|
|
|
|
if (slots !== void 0) {
|
|
|
|
instance.slots = slots
|
|
|
|
}
|
|
|
|
}
|