Vue3:用渲染函数渲染带插槽嵌套组件,为何代码不生效?
1. 插槽传递未做正确映射
Vue3的render函数中,直接将父组件的$slots传给动态渲染的AppItem1/AppItem2是无效的。作为中间组件,AppItem需要手动将自身接收的所有插槽(包括默认插槽和具名插槽)一一透传给目标组件,且每个插槽必须包装成返回VNode的函数,不能直接传递VNode数组。
错误示例:
// 错误:未处理插槽透传 render() { const Comp = `AppItem${this.level}` return h(Comp) }
正确写法:
render() { // 确保使用组件对象而非字符串 const TargetComp = this[`AppItem${this.level}`] return h(TargetComp, {}, { default: () => this.$slots.default?.(), // 按实际需求透传所有具名插槽 header: () => this.$slots.header?.(), footer: () => this.$slots.footer?.() }) }
2. 动态组件引用方式错误
你大概率直接用字符串拼接的组件名调用h函数了(比如h('AppItem' + this.level))——Vue3的h函数需要传入组件对象而非字符串。要么在AppItem的components选项中注册AppItem1/AppItem2,要么直接导入组件后使用。
3. 嵌套组件的插槽透传断层
AppItem1/AppItem2内部嵌套了AppBlock,但如果AppItem1的模板没有将自身接收的插槽透传给AppBlock,即使AppItem传对了插槽,最终也无法在AppBlock中显示。比如AppItem1的模板需要这样写:
<template> <AppBlock> <template #default> <slot /> <!-- 透传默认插槽给AppBlock --> </template> <template #header> <slot name="header" /> <!-- 对应透传具名插槽 --> </template> </AppBlock> </template>
4. 对Vue3 render函数插槽API理解偏差
很多人会错误地将插槽写成default: this.$slots.default,但Vue3要求插槽对象的每个值必须是返回VNode的函数,否则插槽无法响应数据更新,渲染逻辑也会出错。必须用() => this.$slots.xxx?.()的形式包裹。
5. level属性未做响应式处理
如果level不是响应式的(比如只是普通变量,不是props也不是用ref/reactive声明的),当level变化时render函数不会重新执行,组件自然不会切换为对应的AppItem1/AppItem2。要确保level是AppItem的props(props天生响应式),或是用ref声明的变量。
内容的提问来源于stack exchange,提问作者Paulo R.

