v-if 不能直接写在 标签上,因为 是内容出口而非容器,加 v-if 会导致插槽内容未被收集、this.$slots 为空且无报错;应包裹在外部容器(如 )或下沉至插槽内部元素中。

插槽条件渲染不生效,八成是 v-if 直接写在了 <slot></slot> 标签上——它不是容器,而是出口,v-if 一加,整个出口就被移除了,父组件传的内容压根没机会进来。
为什么 v-if 放在 <slot></slot> 上就失效
<slot></slot> 是 Vue 的内容“转发点”,不是 DOM 容器。当 v-if="false" 绑定在 <slot></slot> 上时,Vue 会直接跳过这个节点的编译和挂载,导致:
- 父组件传入的插槽内容不会被收集、也不会进入
$slots - 子组件内部根本收不到任何插槽内容,
this.$slots.xxx为undefined - 控制台无报错,页面留白,极难排查
v-if 应该放在哪才安全
必须包裹插槽,而不是作用于插槽本身。常见正确写法:
- 用
<div v-if="show"><slot name="header"></slot></div>—— 外层容器控制显隐 - 在
<template v-if="show"><template v-slot:header>...</template></template>—— 尤其适用于 uni-app 小程序(H5 正常但小程序白屏时优先试这个) - 把
v-if下沉到插槽内部标签里,比如<u-icon v-if="isLink" name="arrow-right"></u-icon>,避免影响插槽结构
作用域插槽里 v-if 更容易出错
作用域插槽的数据(如 :row="row")可能尚未传入,v-if="row.id" 就会报 Cannot read property 'id' of undefined:
- Vue 3 推荐用可选链:
v-if="row?.id" - Vue 2 用防御性判断:
v-if="row && row.id" - 或在 props 中设默认值:
row: { type: Object, default: () => ({}) }
el-table / uview 等封装组件要防缓存干扰
这类组件内部会对插槽做预编译或实例缓存,v-if 直接控制插槽会导致 DOM 复用异常:
- 表头图标不更新、操作列文字错乱、列宽崩塌
- 控制台报
cannot read property 'renderHeader' of undefined - 解决办法:给
<el-table></el-table>或<el-table-column></el-table-column>加唯一:key,比如:key="tableKey"(每次数据变更时更新) - 或者统一用
<div> 包裹插槽内容,切断直接绑定 <p>最麻烦的不是写错,而是它不报错——你得盯着 <code>$slots对象是否存在、是否为空,才能确认是不是v-if把出口关掉了。











