fix(slots): should render fallback content when slot content contains no valid nodes (#2485)
fix #2347, fix #2461
This commit is contained in:
parent
cf7f1dbc9b
commit
ce4915d8be
@ -5,7 +5,8 @@ import {
|
||||
createVNode,
|
||||
openBlock,
|
||||
createBlock,
|
||||
Fragment
|
||||
Fragment,
|
||||
createCommentVNode
|
||||
} from '../../src'
|
||||
import { PatchFlags } from '@vue/shared/src'
|
||||
|
||||
@ -47,4 +48,31 @@ describe('renderSlot', () => {
|
||||
const templateRendered = renderSlot({ default: slot }, 'default')
|
||||
expect(templateRendered.dynamicChildren!.length).toBe(1)
|
||||
})
|
||||
|
||||
// #2347 #2461
|
||||
describe('only render valid slot content', () => {
|
||||
it('should ignore slots that are all comments', () => {
|
||||
let fallback
|
||||
const vnode = renderSlot(
|
||||
{ default: () => [createCommentVNode('foo')] },
|
||||
'default',
|
||||
undefined,
|
||||
() => [(fallback = h('fallback'))]
|
||||
)
|
||||
expect(vnode.children).toEqual([fallback])
|
||||
expect(vnode.patchFlag).toBe(PatchFlags.BAIL)
|
||||
})
|
||||
|
||||
it('should ignore invalid slot content generated by nested slot', () => {
|
||||
let fallback
|
||||
const vnode = renderSlot(
|
||||
{ default: () => [renderSlot({}, 'foo')] },
|
||||
'default',
|
||||
undefined,
|
||||
() => [(fallback = h('fallback'))]
|
||||
)
|
||||
expect(vnode.children).toEqual([fallback])
|
||||
expect(vnode.patchFlag).toBe(PatchFlags.BAIL)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Data } from '../component'
|
||||
import { Slots, RawSlots } from '../componentSlots'
|
||||
import { Comment, isVNode } from '../vnode'
|
||||
import {
|
||||
VNodeArrayChildren,
|
||||
openBlock,
|
||||
@ -42,15 +43,31 @@ export function renderSlot(
|
||||
// `renderSlot` we can be sure that it's template-based so we can force
|
||||
// enable it.
|
||||
isRenderingCompiledSlot++
|
||||
const rendered = (openBlock(),
|
||||
createBlock(
|
||||
openBlock()
|
||||
const validSlotContent = slot && ensureValidVNode(slot(props))
|
||||
const rendered = createBlock(
|
||||
Fragment,
|
||||
{ key: props.key },
|
||||
slot ? slot(props) : fallback ? fallback() : [],
|
||||
(slots as RawSlots)._ === SlotFlags.STABLE
|
||||
validSlotContent || (fallback ? fallback() : []),
|
||||
validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE
|
||||
? PatchFlags.STABLE_FRAGMENT
|
||||
: PatchFlags.BAIL
|
||||
))
|
||||
)
|
||||
isRenderingCompiledSlot--
|
||||
return rendered
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user