Vue2作用域插槽如何向父组件暴露子组件内部的数据供自定义渲染

作者:袖梨 2026-08-19

作用域插槽是Vue 2中父组件获取子组件内部数据并自定义渲染的核心机制,子组件通过v-bind在slot上绑定数据,父组件用v-slot解构接收并在自身作用域直接使用。

作用域插槽在 Vue 2 中是让父组件拿到子组件内部数据、实现自定义渲染的关键机制。它不是简单地“塞内容进去”,而是“带数据地交出渲染权”。

子组件负责发数据,父组件负责收数据并决定怎么画

子组件怎么把数据传出去

子组件在 <slot> 标签上用 slot-scope(Vue 2.6 之前)或 v-bind(Vue 2.6+ 推荐)绑定变量,把内部状态、循环项、索引等“托付”给插槽。

  1. Vue 2.5 及更早写法(已过时但需兼容时可见):

    <slot :user="currentUser" :index="i" slot-scope="props"></slot>
  2. Vue 2.6+ 正确写法(推荐):

    <slot :user="currentUser" :index="i"></slot>

    注意:这里没有 slot-scope,也不需要 props;绑定的是真实数据,不是占位符。

关键点:

  1. 必须显式用 :v-bind: 绑定属性,比如 :user="xxx",否则父组件收不到
  2. 可以传任意数量的属性,支持对象、数组、布尔值、方法(谨慎暴露方法)
  3. 插槽必须有绑定,空 <slot></slot> 是普通插槽,不带数据

父组件怎么接收并使用这些数据

父组件用 v-slot(或简写 #default)解构接收,变量就在当前模板作用域里直接可用。

<ChildComponent :list="users"><template v-slot:default="{ user, index }"><div class="item"><strong>{{ user.name }}</strong><span>第 {{ index + 1 }} 位</span><small v-if="user.isAdmin">(管理员)</small></div></template></ChildComponent>

常见写法变体:

  1. 解构多个字段:v-slot="{ user, index, isActive }"
  2. 只传一个对象,不解构:v-slot="slotProps" → 用 {{ slotProps.user.name }}
  3. 具名作用域插槽:v-slot:header="{ title }",对应子组件 <slot name="header" :title="pageTitle"></slot>
  4. 默认插槽不能省略 v-slot:default#default,直接写在标签内会失效

实际场景:列表项样式完全由父组件控制

假设子组件只管请求和遍历用户数据,不关心怎么展示:

<!-- UserList.vue(子组件) --><template><ul class="user-list"><li v-for="(u, i) in users" :key="u.id"><slot :user="u" :index="i" :is-even="i % 2 === 0"></slot></li></ul></template>

父组件自由定制:

<UserList :users="data"><template #default="{ user, isEven }"><div :class="{ 'highlight': isEven }">? {{ user.name }} —— {{ user.email }}</div></template></UserList>

容易踩的坑

  1. slot-scope 在 Vue 2.6+ 已废弃,混用会导致编译警告甚至不生效
  2. 父组件没写 v-slot,哪怕子组件绑了数据,也拿不到——作用域插槽必须显式接收
  3. 数据响应式没问题:user 是响应式对象,父组件中修改 user.xxx 会同步影响子组件(除非深度冻结),但一般只读使用更安全
  4. 不要用 refthis.$refs.xxx.users 替代:耦合重、无法精准对应到某一项、非声明式、难维护

本质上,作用域插槽是一次声明式的“数据委托”,子组件专注逻辑,父组件掌控视图,各司其职。

相关文章

精彩推荐