vue3-yuanma/packages/runtime-core/src/componentSlots.ts
2019-08-30 15:34:57 -04:00

75 lines
2.2 KiB
TypeScript

import { ComponentInstance, currentInstance } from './component'
import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode'
import { isArray, isFunction } from '@vue/shared'
import { ShapeFlags } from './shapeFlags'
import { warn } from './warning'
export type Slot = (...args: any[]) => VNode[]
export type Slots = Readonly<{
[name: string]: Slot
}>
export type RawSlots = {
[name: string]: unknown
}
const normalizeSlotValue = (value: unknown): VNode[] =>
isArray(value)
? value.map(normalizeVNode)
: [normalizeVNode(value as VNodeChild)]
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))
}
export function resolveSlots(
instance: ComponentInstance,
children: NormalizedChildren
) {
let slots: Slots | void
if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
if ((children as any)._normalized) {
// pre-normalized slots object generated by compiler
slots = children as Slots
} else {
slots = {}
for (const key in children as RawSlots) {
let value = (children as RawSlots)[key]
if (isFunction(value)) {
;(slots as any)[key] = normalizeSlot(key, value)
} else {
if (__DEV__) {
warn(
`Non-function value encountered for slot "${key}". ` +
`Prefer function slots for better performance.`
)
}
value = normalizeSlotValue(value)
;(slots as any)[key] = () => value
}
}
}
} else if (children !== null) {
// non slot object children (direct value) passed to a component
if (__DEV__) {
warn(
`Non-function value encountered for default slot. ` +
`Prefer function slots for better performance.`
)
}
const normalized = normalizeSlotValue(children)
slots = { default: () => normalized }
}
if (slots !== void 0) {
instance.slots = slots
}
}