Vue slots 是基于内容分发的渲染机制,其默认内容仅在父组件完全未提供任何 slot 内容(包括空格、换行)时生效,且作用域插槽的默认内容无法访问子组件数据,需用 v-if 配合 $slots 判断后备逻辑。

Vue.js 中的 slots 并非只是“插槽容器”,它是一套基于内容分发(Content Distribution)的渲染机制,其默认内容与后备渲染(fallback content)逻辑直接影响组件的可复用性与健壮性。理解它的执行时机、作用域和回退条件,才能写出真正灵活、不易出错的封装组件。
默认内容只在 slot 无传入内容时才渲染
很多人误以为 <slot>默认文本</slot> 是“兜底展示”,其实它仅在父组件未向该 slot 提供任何内容时才生效。一旦父组件写了 <template #default>...</template> 或直接写子元素,哪怕内容为空(如 <MyButton></MyButton>),默认内容也不会出现。
- ✅ 正确触发默认内容:
<MyButton />(完全不写内容) - ❌ 不触发默认内容:
<MyButton></MyButton>(空标签,但已声明 slot 内容节点) - ⚠️ 注意:空格、换行符也被视为文本节点,
<MyButton> </MyButton>同样会阻止默认内容渲染
作用域插槽中默认内容无法访问子组件数据
当使用具名或作用域插槽(如 <slot name="item" :item="item"></slot>)时,slot 内的默认内容运行在**父组件作用域**,无法直接使用 item 等子组件暴露的数据。若需在后备内容中使用子组件状态,必须显式通过 v-if + 插槽参数判断是否提供内容,再配合 v-else 渲染后备结构。
- 错误写法:
<slot name="item" :item="item">{{ item?.label }}</slot>(item在父作用域未定义) - 推荐写法:
<slot name="item" :item="item"></slot> <template v-if="$slots.item === undefined"> <font color="#666">暂无数据</font> </template>
多个插槽共存时,每个 slot 独立判断后备逻辑
一个组件可定义多个具名插槽(如 header、footer、default),它们的默认内容互不影响。即使 header 有内容而 footer 没有,也只会渲染 footer 的默认内容,其他插槽照常工作。
立即学习“前端免费学习笔记(深入)”;
- 子组件中可安全写:
<header><slot name="header">默认标题</slot></header> - 父组件只需提供需要覆盖的部分:
<MyCard><template #header>自定义标题</template></MyCard>,其余插槽自动回退 - 无需为每个插槽都写
v-if判断,Vue 内部已按插槽名称独立处理
编译时静态分析决定默认内容是否保留
Vue 3 的编译器会对 <slot> 进行静态分析:若确定父组件未提供对应内容(如编译期可判定无 #xxx 或匿名内容),则默认内容会被保留在渲染函数中;否则整个 <slot> 节点被替换为父传入的内容,原始默认内容彻底丢弃——它不是“隐藏”,而是根本不会进入 VNode 树。
- 这意味着:不能靠 CSS
display: none控制默认内容显隐,它可能压根没被创建 - 调试技巧:在开发者工具中查看组件实际渲染的 DOM,确认默认内容是否存在,比看模板更可靠
- 动态插槽名(如
:name="slotName")会让编译器无法静态判断,此时默认内容行为更依赖运行时逻辑


















