vue3-core/packages/runtime-core/src/helpers/renderSlot.ts

98 lines
2.7 KiB
TypeScript
Raw Normal View History

2019-10-22 23:26:48 +08:00
import { Data } from '../component'
import { Slots, RawSlots } from '../componentSlots'
2021-07-13 03:32:38 +08:00
import {
ContextualRenderFn,
currentRenderingInstance
} from '../componentRenderContext'
import {
Comment,
isVNode,
VNodeArrayChildren,
openBlock,
createBlock,
Fragment,
VNode
} from '../vnode'
import { PatchFlags, SlotFlags } from '@vue/shared'
2020-02-07 14:06:51 +08:00
import { warn } from '../warning'
2021-07-13 03:32:38 +08:00
import { createVNode } from '@vue/runtime-core'
import { isAsyncWrapper } from '../apiAsyncComponent'
2019-09-28 08:29:20 +08:00
/**
* Compiler runtime helper for rendering `<slot/>`
* @private
*/
2019-09-28 08:29:20 +08:00
export function renderSlot(
slots: Slots,
name: string,
2019-10-22 23:26:48 +08:00
props: Data = {},
2019-09-28 08:29:20 +08:00
// this is not a user-facing function, so the fallback is always generated by
// the compiler and guaranteed to be a function returning an array
fallback?: () => VNodeArrayChildren,
noSlotted?: boolean
): VNode {
if (
currentRenderingInstance!.isCE ||
(currentRenderingInstance!.parent &&
isAsyncWrapper(currentRenderingInstance!.parent) &&
currentRenderingInstance!.parent.isCE)
) {
2021-07-13 03:32:38 +08:00
return createVNode(
'slot',
name === 'default' ? null : { name },
fallback && fallback()
)
}
2020-02-07 14:06:51 +08:00
let slot = slots[name]
if (__DEV__ && slot && slot.length > 1) {
2020-02-07 14:06:51 +08:00
warn(
`SSR-optimized slot function detected in a non-SSR-optimized render ` +
`function. You need to mark this component with $dynamic-slots in the ` +
`parent template.`
)
slot = () => []
}
// a compiled slot disables block tracking by default to avoid manual
// invocation interfering with template-based block tracking, but in
// `renderSlot` we can be sure that it's template-based so we can force
// enable it.
if (slot && (slot as ContextualRenderFn)._c) {
;(slot as ContextualRenderFn)._d = false
}
openBlock()
const validSlotContent = slot && ensureValidVNode(slot(props))
const rendered = createBlock(
Fragment,
{ key: props.key || `_${name}` },
validSlotContent || (fallback ? fallback() : []),
validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE
? PatchFlags.STABLE_FRAGMENT
: PatchFlags.BAIL
)
if (!noSlotted && rendered.scopeId) {
rendered.slotScopeIds = [rendered.scopeId + '-s']
}
if (slot && (slot as ContextualRenderFn)._c) {
;(slot as ContextualRenderFn)._d = true
}
return rendered
2019-09-28 08:29:20 +08:00
}
function ensureValidVNode(vnodes: VNodeArrayChildren) {
return vnodes.some(child => {
if (!isVNode(child)) return true
if (child.type === Comment) return false
if (
child.type === Fragment &&
!ensureValidVNode(child.children as VNodeArrayChildren)
)
return false
return true
})
? vnodes
: null
}