Vue3 Slot API 怎么用?从基础到实战一次讲透
插槽在Vue3里扮演啥角色?和Vue2比有啥进化?
插槽的核心作用是让父组件给子组件传递“结构”,比如子组件是个“卡片框架”,父组件想往卡片里塞标题、按钮、列表这些自定义内容,就需要插槽来实现组件间的“结构通信”。
Vue3 对插槽的优化主要体现在语法统一和性能提升上:
- 语法层面:Vue2 里作用域插槽要用
slot-scope(后来也支持v-slot),写法分散;Vue3 彻底统一用v-slot(缩写 ),不管是默认插槽、具名插槽还是作用域插槽,都能通过v-slot简洁表达。 - 性能层面:Vue3 编译时对插槽做了优化,减少运行时的响应式依赖追踪,渲染更高效。
举个简单对比:
Vue2 写作用域插槽可能这样:
<ChildComponent>
<template slot-scope="props">
{{ props.msg }}
</template>
</ChildComponent>
Vue3 则统一成:
<ChildComponent>
<template #default="props">
{{ props.msg }}
</template>
</ChildComponent>
<!-- 甚至更简洁:只有默认插槽时,直接绑定v-slot -->
<ChildComponent v-slot="props">
{{ props.msg }}
</ChildComponent>
默认插槽和具名插槽,Vue3里怎么写最顺手?
默认插槽:“单区域”自定义内容
子组件里放一个 <slot>,可以写“兜底内容”(父组件没传内容时显示),比如做个卡片组件 MyCard:
<!-- 子组件 MyCard -->
<template>
<div class="card">
<slot>这里是默认内容,父组件没传内容时显示</slot>
</div>
</template>
父组件用的时候,直接在 MyCard 标签里塞内容:
<MyCard> <h2>我是父组件传的标题</h2> <p>这里是卡片正文...</p> </MyCard>
具名插槽:“多区域”精准自定义
如果子组件有多个插槽区域(比如头部、主体、底部),就得用具名插槽,子组件给 <slot> 加 name 属性,父组件用 #插槽名 指定内容。
比如给 MyCard 加头部、底部插槽:
<!-- 子组件 MyCard -->
<template>
<div class="card">
<header>
<slot name="header"></slot> <!-- 头部插槽 -->
</header>
<main>
<slot></slot> <!-- 默认插槽(name省略即default) -->
</main>
<footer>
<slot name="footer"></slot> <!-- 底部插槽 -->
</footer>
</div>
</template>
时,用 <template #插槽名> 精准对应:
<MyCard>
<template #header>
<h1>这是卡片头部</h1>
</template>
<!-- 默认插槽不用template包裹,直接写内容也能传 -->
<p>这是卡片主体内容</p>
<template #footer>
<button>操作按钮</button>
</template>
</MyCard>
作用域插槽咋玩?Vue3和之前版本差异多大?
作用域插槽是子组件给插槽传数据,父组件拿数据自定义渲染,比如子组件有列表数据,想让父组件决定每一项咋显示。
子组件传数据:给<slot>绑属性
子组件 MyList 里,循环渲染列表项时,给 <slot> 传递 item 和 index:
<!-- 子组件 MyList -->
<template>
<ul>
<li v-for="(item, index) in list" :key="item.id">
<slot :item="item" :index="index"></slot> <!-- 传item和index给插槽 -->
</li>
</ul>
</template>
<script setup>
const list = [/* 假设是列表数据 */]
</script>
父组件拿数据:v-slot="参数" 接收
父组件用 #default="slotProps" 接收子组件传的参数(slotProps 是个对象,包含 item 和 index):
<MyList>
<template #default="slotProps">
{{ slotProps.index }} - {{ slotProps.item.name }}
</template>
</MyList>
如果是具名的作用域插槽(比如子组件 <slot name="custom" :data="data"></slot>),父组件就用 <template #custom="props"> 接收。
和Vue2的区别
Vue2 里作用域插槽得用 slot-scope,写法分散易混乱;Vue3 统一用 v-slot 的参数,语法更集中,Vue3 编译时对作用域插槽做了性能优化,减少不必要的响应式追踪,渲染更高效。
插槽的高级玩法:动态、组合、FallBack怎么用?
动态插槽名:插槽名由变量控制
如果插槽名是动态的(比如用户操作切换显示区域),Vue3 支持 <template #[变量]>,示例:
<template>
<button @click="slotName = 'header'">显示头部</button>
<button @click="slotName = 'footer'">显示底部</button>
<MyComponent>
<template #[slotName]="props">
{{ props.content }} <!-- 根据slotName动态渲染对应插槽 -->
</template>
</MyComponent>
</template>
<script setup>
import { ref } from 'vue'
const slotName = ref('header')
</script>
FallBack内容:插槽的“兜底方案”
子组件 <slot> 里可以写默认内容,父组件没传内容时自动显示,比如弹窗组件的头部插槽:
<slot name="header"> <h2>默认标题</h2> <!-- 父组件没传#header时,显示这个 --> </slot>
插槽组合:多个插槽协同工作
一个组件里可以同时用默认插槽和多个具名插槽,父组件分别传内容,子组件负责布局,比如弹窗组件 Modal:
<!-- 子组件 Modal -->
<template>
<div class="modal">
<div class="modal-header">
<slot name="header">默认标题</slot>
</div>
<div class="modal-body">
<slot></slot> <!-- 默认插槽 -->
</div>
<div class="modal-footer">
<slot name="footer">
<button>确定</button>
<button>取消</button>
</slot>
</div>
</div>
</template>
父组件用的时候,可只传部分插槽,其他用默认:
<Modal>
<template #header>
<h1>自定义标题</h1>
</template>
<p>弹窗主体内容...</p>
<!-- footer没传,用子组件默认按钮 -->
</Modal>
实际项目中,插槽能解决哪些开发痛点?
插槽的核心价值是让组件更灵活、更易复用,以下场景特别实用:
组件解耦:UI库基础组件的“定制化”
UI 库的“卡片、弹窗、下拉框”这类组件,只负责结构和样式,内容由父组件通过插槽自定义,避免组件里写满 if-else 来适配不同场景,让组件更“纯净”。
灵活渲染:列表/表格的“自定义列”
表格组件想让每一列的渲染逻辑由父组件决定?用作用域插槽!子组件传每行数据给插槽,父组件自定义渲染(比如给某列加按钮、图标、富文本)。
示例:表格组件 Table 让用户自定义列:
<!-- 子组件 Table -->
<template>
<table>
<tbody>
<tr v-for="row in data" :key="row.id">
<td v-for="col in columns" :key="col.key">
<slot :name="col.key" :row="row" :col="col">
{{ row[col.key] }} <!-- 兜底内容 -->
</slot>
</td>
</tr>
</tbody>
</table>
</template>
<script setup>
const props = defineProps(['columns', 'data'])
</script>
父组件自定义“姓名列”和“操作列”:
<Table :columns="columns" :data="tableData">
<template #name="props">
<img :src="props.row.avatar" /> {{ props.row.name }}
</template>
<template #action="props">
<button @click="edit(props.row)">编辑</button>
</template>
</Table>
布局复用:“框架型组件”的内容自由组合
左右布局、栅格布局、选项卡”这类组件,用插槽让用户自由填充内容,布局结构复用,内容灵活组合。
减少Props传递:复杂结构直接“插”
有些场景传“HTML结构”比传“数据”更方便(比如带样式的按钮组、富文本块),用插槽直接传结构,不用拆分成多个 props,代码更简洁。
Vue3 Slot API 学透了有多香?
Vue3 的 Slot API 把“传结构”这件事变得更简洁、更灵活、更高效:
- 语法上,
v-slot统一了所有插槽的写法, 缩写让代码更简洁; - 功能上,作用域插槽、动态插槽、FallBack 内容覆盖了“自定义渲染、动态切换、兜底方案”等场景;
- 实战中,能让组件解耦、复用性拉满,还能减少冗余代码。
不管是写业务组件(如商品卡片、弹窗),还是封装 UI 库,插槽都是“让组件活起来”的关键武器,把基础用法和高级技巧练熟,组件开发效率能提升一大截~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网

