作用域插槽传递多个对象数据应统一用v-bind="row"绑定响应式对象,父组件通过v-slot:default="row"接收并展开透传,避免手动逐个绑定或硬解构,兼顾响应式、可维护性与扩展性。

作用域插槽必须用 v-bind 绑定整个对象
直接给 <slot></slot> 写多个属性(比如 :id="item.id" :name="item.name" :tags="item.tags")看着直观,但字段一多就容易漏、难维护,还可能因响应式丢失导致父组件收不到更新。
- 子组件中统一用
v-bind="row",其中row是一个响应式对象(来自data、computed或props) - 不要手动展开嵌套字段,比如
:profile="item.profile" :avatar="item.profile.avatar"——这会让父组件无法感知profile内部变化 - 如果
row可能为null或undefined,写成v-bind="row ?? {}"防止运行时报错Cannot read properties of null
v-slot 接收时优先用对象解构或展开,别硬拆
父组件里写 v-slot:default="{ id, name, tags }" 没问题,但字段超过 4 个、或未来可能动态增减时,这种写法会快速变成维护噩梦。
- 推荐用
v-slot:default="row"接收整个对象,再用v-bind="row"透传给子组件(如<user-card v-bind="row"></user-card>) - 需要加额外上下文(比如权限开关)时,直接合并:
v-bind="{ ...row, editable: isOwner }" - 避免在
v-slot内部对row.tags做v-for或复杂计算——这些逻辑应移到computed或子组件内部,否则每次row更新都会触发重渲染
多层传递时,中间组件只做“管道”,不加工数据
从 A → B → C 的 slot 跨层传递,常见错误是中间组件 B 主动解构再重组,比如 v-slot:action="{ id, name }" 然后又 <slot name="action" :id="id" :name="name"></slot>。这不仅冗余,还切断了响应式链。
- B 组件只需原样透传:
<slot name="action" v-bind="slotProps"></slot>,其中slotProps来自 C 的v-bind - Vue 3 原生支持这种透传,不需要
provide/inject或额外 state - 如果 B 需要注入自己的字段(比如
locale),用展开合并:v-bind="{ ...slotProps, locale: 'zh-CN' }",而不是覆盖
嵌套对象和数组的边界必须手动守
v-bind="obj" 不会深拷贝,也不会自动监听嵌套变更——这是最容易被忽略的性能隐患。
- 如果
row包含user: { profile: { avatar: '' } },父组件用{{ row.user.profile.avatar }}是安全的;但若子组件内部做了row.user.profile = newProfile,父组件不会响应 - 需要深层响应时,要么让子组件暴露
update:profile事件,要么用toRefs+computed在父组件做代理 - 大型数组(如
row.logs)不要直接展开传入列表组件,先用computed截取前 20 条或加防抖
v-bind 和展开,其余交给组件自身消化。越想省事手动拆,后面越容易掉坑里。











