2019-10-22 23:26:48 +08:00
|
|
|
import { Data } from '../component'
|
2020-07-16 08:12:49 +08:00
|
|
|
import { Slots, RawSlots } from '../componentSlots'
|
2020-11-27 00:35:45 +08:00
|
|
|
import { Comment, isVNode } from '../vnode'
|
2019-10-04 00:03:14 +08:00
|
|
|
import {
|
2020-01-29 11:58:02 +08:00
|
|
|
VNodeArrayChildren,
|
2019-10-04 00:03:14 +08:00
|
|
|
openBlock,
|
|
|
|
createBlock,
|
|
|
|
Fragment,
|
|
|
|
VNode
|
|
|
|
} from '../vnode'
|
2020-07-16 08:12:49 +08:00
|
|
|
import { PatchFlags, SlotFlags } from '@vue/shared'
|
2020-02-07 14:06:51 +08:00
|
|
|
import { warn } from '../warning'
|
2019-09-28 08:29:20 +08:00
|
|
|
|
2020-08-22 00:47:45 +08:00
|
|
|
export let isRenderingCompiledSlot = 0
|
2020-09-02 00:38:47 +08:00
|
|
|
export const setCompiledSlotRendering = (n: number) =>
|
|
|
|
(isRenderingCompiledSlot += n)
|
2020-08-06 22:16:13 +08:00
|
|
|
|
2020-05-01 05:04:35 +08:00
|
|
|
/**
|
2020-07-17 23:24:12 +08:00
|
|
|
* Compiler runtime helper for rendering `<slot/>`
|
2020-06-11 02:57:21 +08:00
|
|
|
* @private
|
2020-05-01 05:04:35 +08:00
|
|
|
*/
|
2019-09-28 08:29:20 +08:00
|
|
|
export function renderSlot(
|
2020-02-25 12:05:35 +08:00
|
|
|
slots: Slots,
|
2019-10-04 03:09:09 +08:00
|
|
|
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
|
2020-04-23 04:52:41 +08:00
|
|
|
// the compiler and guaranteed to be a function returning an array
|
2021-03-06 01:12:49 +08:00
|
|
|
fallback?: () => VNodeArrayChildren,
|
|
|
|
hasSlotted?: boolean
|
2019-10-04 00:03:14 +08:00
|
|
|
): VNode {
|
2020-02-07 14:06:51 +08:00
|
|
|
let slot = slots[name]
|
|
|
|
|
2020-02-25 12:05:35 +08:00
|
|
|
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 = () => []
|
|
|
|
}
|
|
|
|
|
2020-08-06 22:16:13 +08:00
|
|
|
// 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.
|
2020-08-22 00:47:45 +08:00
|
|
|
isRenderingCompiledSlot++
|
2020-11-27 00:35:45 +08:00
|
|
|
openBlock()
|
|
|
|
const validSlotContent = slot && ensureValidVNode(slot(props))
|
|
|
|
const rendered = createBlock(
|
2020-08-06 22:16:13 +08:00
|
|
|
Fragment,
|
2020-11-28 03:35:38 +08:00
|
|
|
{ key: props.key || `_${name}` },
|
2020-11-27 00:35:45 +08:00
|
|
|
validSlotContent || (fallback ? fallback() : []),
|
|
|
|
validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE
|
2020-08-06 22:16:13 +08:00
|
|
|
? PatchFlags.STABLE_FRAGMENT
|
|
|
|
: PatchFlags.BAIL
|
2020-11-27 00:35:45 +08:00
|
|
|
)
|
2021-03-06 01:12:49 +08:00
|
|
|
if (hasSlotted && rendered.scopeId) {
|
2021-03-06 00:10:06 +08:00
|
|
|
rendered.slotScopeIds = [rendered.scopeId + '-s']
|
|
|
|
}
|
2020-08-22 00:47:45 +08:00
|
|
|
isRenderingCompiledSlot--
|
2020-08-06 22:16:13 +08:00
|
|
|
return rendered
|
2019-09-28 08:29:20 +08:00
|
|
|
}
|
2020-11-27 00:35:45 +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
|
|
|
|
}
|