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,
|
createVNode,
|
||||||
openBlock,
|
openBlock,
|
||||||
createBlock,
|
createBlock,
|
||||||
Fragment
|
Fragment,
|
||||||
|
createCommentVNode
|
||||||
} from '../../src'
|
} from '../../src'
|
||||||
import { PatchFlags } from '@vue/shared/src'
|
import { PatchFlags } from '@vue/shared/src'
|
||||||
|
|
||||||
@ -47,4 +48,31 @@ describe('renderSlot', () => {
|
|||||||
const templateRendered = renderSlot({ default: slot }, 'default')
|
const templateRendered = renderSlot({ default: slot }, 'default')
|
||||||
expect(templateRendered.dynamicChildren!.length).toBe(1)
|
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 { Data } from '../component'
|
||||||
import { Slots, RawSlots } from '../componentSlots'
|
import { Slots, RawSlots } from '../componentSlots'
|
||||||
|
import { Comment, isVNode } from '../vnode'
|
||||||
import {
|
import {
|
||||||
VNodeArrayChildren,
|
VNodeArrayChildren,
|
||||||
openBlock,
|
openBlock,
|
||||||
@ -42,15 +43,31 @@ export function renderSlot(
|
|||||||
// `renderSlot` we can be sure that it's template-based so we can force
|
// `renderSlot` we can be sure that it's template-based so we can force
|
||||||
// enable it.
|
// enable it.
|
||||||
isRenderingCompiledSlot++
|
isRenderingCompiledSlot++
|
||||||
const rendered = (openBlock(),
|
openBlock()
|
||||||
createBlock(
|
const validSlotContent = slot && ensureValidVNode(slot(props))
|
||||||
|
const rendered = createBlock(
|
||||||
Fragment,
|
Fragment,
|
||||||
{ key: props.key },
|
{ key: props.key },
|
||||||
slot ? slot(props) : fallback ? fallback() : [],
|
validSlotContent || (fallback ? fallback() : []),
|
||||||
(slots as RawSlots)._ === SlotFlags.STABLE
|
validSlotContent && (slots as RawSlots)._ === SlotFlags.STABLE
|
||||||
? PatchFlags.STABLE_FRAGMENT
|
? PatchFlags.STABLE_FRAGMENT
|
||||||
: PatchFlags.BAIL
|
: PatchFlags.BAIL
|
||||||
))
|
)
|
||||||
isRenderingCompiledSlot--
|
isRenderingCompiledSlot--
|
||||||
return rendered
|
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