useSlots().default not null
Version
3.2.33
Reproduction link
Steps to reproduce
the App component has a slot, and the v-if of the slot passed in by Child is false
What is expected?
I expected the console "slotDefault" is null
What is actually happening?
when I console.log "slotDefault" is not null
I just use like this
in the Dialog Component log slot.default is not null,but just like your example ,use named slot can work,I want to know why?
You can use the "named slot" pattern with the default slot as well:
<Child>
<template v-slot:default v-if="someCondition">
</template>
</Child>
Because the v-if
, when being false, leaves a placeholder in the vdom so it can later, when its true, be replaced with the actual content.
A similar thing happens when you have a v-for loop that has zero items - it still creates a Fragment
vnode.
I just want to know why use default slot the console in my Dialog component is not null
the code
<template v-if="false">App</template>
is also a vnode.
Because the
v-if
, when being false, leaves a placeholder in the vdom so it can later, when its true, be replaced with the actual content.A similar thing happens when you have a v-for loop that has zero items - it still creates a
Fragment
vnode.
why the named slot did not leave vnode?
I don't think you understand me
1:<template #default> <div v-if="false"/> </template>
2:<template #name> <div v-if="false"/> </template>
Both of the above:the first one slot.default is not null,the second slot.name is null
I just want to know why the vnode work on defaut slot,but not work on the named slot
both variations you show here behave absolutely identical.The difference is between <Child v-slot:default>
and <template v-slot:default>
.
If you want me to explain more, please provide a playground with a demo of the exact problem you are asking about.
I don't think you understand me
1:<template #default> <div v-if="false"/> </template>
2:<template #name> <div v-if="false"/> </template>
Both of the above:the first one slot.default is not null,the second slot.name is null I just want to know why the vnode work on defaut slot,but not work on the named slot
Let me show some example:
slot.name is not null
slot.default is not null
the parent Component is like this
<template> <slot v-if="slotDefault"></slot> </template>
<script> import {useSlots } from 'vue' const slotDefault = useSlots().default; console.log('slotDefault', slotDefault); // if use deafult slot log is not null,but use named slot log is null </script>
defaut is not undefined, header as named slot is undefined
defaut is not undefined, header as named slot is undefined
Example
The default slot is handled differently from the name slot:
<script setup name="App">
import Dialog from './Dialog.vue'
</script>
<template>
<Dialog>
<template v-if="false"></template>
<template #header v-if="false"></template>
<template #main v-if="false"></template>
</Dialog>
</template>
I recommend you to look at the compiled code, copy the code to the vscode and formate it, you will have a deeper understanding
For your example compile to:
so name slot is undefined
/* Analyzed bindings: {
"Dialog": "setup-const"
} */
import {
Fragment as _Fragment,
openBlock as _openBlock,
createElementBlock as _createElementBlock,
createCommentVNode as _createCommentVNode,
withCtx as _withCtx,
createSlots as _createSlots,
createBlock as _createBlock,
} from 'vue'
import Dialog from './Dialog.vue'
const __sfc__ = {
setup(__props) {
return (_ctx, _cache) => {
return (
_openBlock(),
_createBlock(
Dialog,
null,
_createSlots(
// default slot
{
default: _withCtx(() => [
false
? (_openBlock(), _createElementBlock(_Fragment, { key: 0 }, [], 64 /* STABLE_FRAGMENT */))
: _createCommentVNode('v-if', true),
]),
_: 2 /* DYNAMIC */,
},
// name slot
[
// the value is undefined
false
? {
name: 'header',
fn: _withCtx(() => []),
}
: undefined,
// the value is undefined
false
? {
name: 'main',
fn: _withCtx(() => []),
}
: undefined,
]
),
1024 /* DYNAMIC_SLOTS */
)
)
}
},
}
__sfc__.__file = 'App.vue'
export default __sfc__
<template v-if="..."> != <template v-slot:default v-if="....">
the former is just a way of using v-if, unrelated to slots. so you basically just passed <div v-if>
to the default slot again.
The latter is how you can to define a default slot alongside other named slots.
You can learn more in this section of the docs: https://vuejs.org/guide/components/slots.html#named-slots
<Child>
<template #default v-if="someCondition">
<div>whatever</div>
</template>
</Child>
The above will result in slot.default
being undefined if someCondition is falsy, because the parent doesn't pass a slot function for the default slot to the child.
<Child>
<template v-if="someCondition">
<div>whatever</div>
</template>
</Child>
<!-- as well as: -->
<Child>
<div v-if="someCondition">whatever</div>
</Child>
The two above ways are equivalent, and will both result in a slot function being passed to the child, and that slot function will return a placeholder vnode for the v-if
, so it will not be empty.
Similarly, with v-for:
<Child>
<template v-for="item in [ /* empty array */]">
<div>whatever</div>
</template>
</Child>
<!-- as well as: -->
<Child>
<div v-for="item in [ /* empty array */]">whatever</div>
</Child>
both of these will pass a slot function down, which will return a Fragment vnode representing the v-for loop, even though the loop itself returned 0 elements.
As described in the vue documentation: When a component accepts both a default slot and named slots, all top-level non- nodes are implicitly treated as content for the default slot. I think v-if in div with no name slot should be treated as default slot tag,not as placeholder in vdom,because it is rendered in the default slot position
both <template #default v-if="false"> and are treated as default slot,so that I think the behavior should be the same,Or there shouldn't be have a default slot,It's all called named slot