← 返回题目列表

Vue 插槽和作用域插槽是什么?适合解决什么问题?

高频 中等 第 6 / 27 题 更新于 2026/07/29
Vueslot作用域插槽组件设计

简化版

插槽让父组件把内容传给子组件指定位置,作用域插槽让子组件把数据暴露给父组件决定怎么渲染。它们常用于布局组件、列表组件、表格组件、弹窗组件,让组件既封装结构,又保留内容定制能力。

详细版

默认插槽:

<Card>
  <p>这里是卡片内容</p>
</Card>

具名插槽:

<Card>
  <template #header>标题</template>
  <template #default>正文</template>
</Card>

作用域插槽:

<UserList v-slot="{ user }">
  <span>{{ user.name }}</span>
</UserList>

核心区别是:普通插槽传内容,作用域插槽传“渲染权 + 子组件数据”。

完整版教学

一、插槽解决组件内容可定制的问题

组件封装常遇到一个矛盾:子组件想复用结构,但具体内容又要由父组件决定。 如果全部写死,组件不够灵活;如果全部交给父组件,封装价值又变低。 插槽就是这个折中点。

<!-- 父组件 -->
<BaseCard>
  <p>订单金额:100 元</p>
</BaseCard>
<!-- BaseCard -->
<div class="card">
  <slot />
</div>

这里卡片边框、间距、阴影由 BaseCard 管,内部内容由父组件提供。 这就是“结构由子组件封装,内容由父组件填充”。

二、默认插槽适合单内容区域

默认插槽只有一个主要内容出口。 它适合按钮、卡片、弹窗正文、布局容器等简单场景。 如果父组件没有传内容,子组件还可以提供 fallback 内容。

<button class="btn">
  <slot>提交</slot>
</button>

当父组件写 <BaseButton /> 时显示“提交”。 当父组件写 <BaseButton>保存</BaseButton> 时显示“保存”。 这个设计让组件有默认行为,也允许调用方覆盖。

三、具名插槽适合多区域布局

当组件有多个可定制区域时,需要具名插槽。 例如弹窗通常有 header、body、footer。 具名插槽能让父组件准确填到指定区域。

<BaseModal>
  <template #header>删除确认</template>
  <template #default>确定删除这 3 条记录吗?</template>
  <template #footer>
    <button>取消</button>
    <button>确定</button>
  </template>
</BaseModal>
插槽类型适合场景特点
默认插槽单内容区域写法最简单
具名插槽多区域组件内容位置明确
作用域插槽子传数据给父渲染渲染更灵活

有 3 个区域时,用具名插槽比传 3 个字符串 prop 更灵活,因为 footer 里可以放按钮、图标、权限判断等任意模板。

四、作用域插槽让子组件提供数据,父组件决定视图

作用域插槽的核心是:数据在子组件,模板在父组件。 它特别适合列表、表格、选择器这种“逻辑统一但每行展示不同”的组件。 子组件负责遍历和状态,父组件负责具体怎么显示每一项。

<!-- 子组件 UserList.vue -->
<template>
  <ul>
    <li v-for="user in users" :key="user.id">
      <slot :user="user" :index="user.id" />
    </li>
  </ul>
</template>
<!-- 父组件 -->
<UserList v-slot="{ user }">
  <strong>{{ user.name }}</strong>
  <span>{{ user.role }}</span>
</UserList>

如果有 20 个页面都需要用户列表,但每个页面展示字段不同,作用域插槽能避免写 20 个列表组件。 它把“列表逻辑”和“行模板”拆开了。

五、插槽内容的作用域属于父组件

一个重要原则:插槽模板写在父组件里,所以它能访问父组件作用域。 默认情况下,它不能直接访问子组件内部变量。 如果需要子组件数据,必须通过作用域插槽显式传出。

<Child>
  {{ parentTitle }}
</Child>

上面的 parentTitle 来自父组件。 如果想用子组件里的 item,子组件必须写 <slot :item="item" />。 这能避免作用域混乱,让数据来源更明确。

六、插槽是组件库设计的高频能力

表格组件、表单组件、弹窗组件、布局组件大量使用插槽。 比如表格组件可以提供列配置,也可以用作用域插槽定制单元格。 这样既保证表格的分页、排序、加载逻辑统一,又让业务能自定义渲染。

<DataTable :rows="rows">
  <template #cell-status="{ row }">
    <StatusTag :value="row.status" />
  </template>
</DataTable>

记忆钩子:普通插槽是父给子“内容”,作用域插槽是子给父“数据”,最终由父决定怎么画。

组件库里的插槽越多,不代表设计越好。 太多插槽会让 API 复杂,应该围绕稳定扩展点设计。

七、常见误区与追问

  • 误区:插槽只是把 HTML 传给子组件。 插槽本质是组件内容分发机制,可以传组件、表达式、条件渲染和事件绑定。
  • 误区:插槽内容能随便访问子组件变量。 插槽模板属于父组件作用域,访问子组件数据需要作用域插槽显式传递。
  • 误区:作用域插槽只适合列表。 列表和表格最常见,但选择器、树组件、弹窗 footer、表单项也常用。
  • 追问:具名插槽为什么比多个 prop 灵活? prop 适合数据,插槽适合模板内容,按钮、组件、权限判断都能放进插槽。
  • 追问:作用域插槽会不会破坏封装? 不会,它只暴露子组件愿意暴露的数据,结构和状态逻辑仍由子组件控制。
  • 追问:组件库设计插槽要注意什么? 插槽名要稳定,暴露数据要克制,避免让业务依赖内部实现细节。

八、加强记忆

插槽这题记成“子组件留坑,父组件填内容”。默认插槽填一个坑,具名插槽填多个坑,作用域插槽则是子组件把数据递出来,让父组件决定怎么渲染。回答时用弹窗和表格两个例子,能很好体现组件复用价值。