插槽在Vue 3渲染函数中是函数而非内容,必须调用slots.default()等才能获取VNode数组;h函数接收VNode描述对象,不可直接传入未调用的插槽函数。

渲染函数中插槽不是“写进去”的内容,而是“调用出来”的函数。Vue 3 的 h 函数本身不直接接收 HTML 字符串或模板字符串,它接收的是 VNode 描述对象;而插槽(slots)在 setup 或 render 函数中,本质是一组函数——slots.default()、slots.header()、slots.item({ item }) 等,只有执行它们,才返回真正的 VNode 数组。
插槽在 render 函数里是函数,不是内容
在使用 render() { return h(...) } 编写自定义渲染逻辑时,slots 是通过第二个参数(即 ctx 或解构出的 { slots })传入的。它不是现成的 DOM 片段,也不是字符串,而是一个对象,每个 key 对应一个插槽函数:
-
slots.default可能为undefined,需判断存在性再调用 -
slots.footer是函数,调用后返回 VNode 数组(可能为空) -
slots.item是作用域插槽,调用时需传入响应式数据对象,如slots.item({ item: currentData, index: i })
用 h 包裹插槽调用结果的正确姿势
不能把 slots.default 直接当子节点传给 h,必须调用它:
- ✅ 正确:
h('div', [slots.default && slots.default()]) - ✅ 带条件:
h('section', slots.showHeader ? [slots.header()] : []) - ✅ 作用域插槽:
h('ul', list.map((item, i) => h('li', slots.item?.({ item, index: i }) || [])) - ❌ 错误:
h('div', slots.default)(未调用,传入函数而非 VNode) - ❌ 错误:
h('div', slots.default?.())(若default为undefined,?.() 会返回undefined,但h子节点数组中不能含undefined)
安全调用插槽的实用模式
为避免运行时报错或空数组异常,建议封装可复用的调用逻辑:
立即学习“前端免费学习笔记(深入)”;
- 空值保护:用
slots.xxx?.() ?? []替代裸调用 - 统一 fallback:对缺失插槽提供默认结构,例如
slots.footer?.() || h('p', '暂无底部信息') - 具名插槽映射:用对象映射动态 slot 名,如
const slotMap = { top: 'header', mid: 'default', bottom: 'footer' },配合v-slot:[name]动态语法更易维护 - 工厂函数封装:将常用插槽逻辑抽成函数,如
renderListSlot = (items) => items.map(i => h('div', slots.item?.({ item: i }) || []))
动态插槽名与 h 的协同写法
当插槽名由变量控制(如 const currentSlot = ref('sidebar')),不能直接写 slots[currentSlot.value]——因为响应式变量需在渲染函数内读取,且需确保其值合法:
- 先读取变量:
const name = currentSlot.value - 再安全访问:
const slotFn = name && typeof slots[name] === 'function' ? slots[name] : null - 最后调用:
slotFn?.() ?? [] - 完整示例:
h('aside', slotFn?.({ side: name }) ?? [h('p', '未配置该插槽')])



















