Vue3 中的 Slot(插槽)完整解析
Slot 是一种组件内容分发机制,让父组件将内容注入到子组件内部的指定位置,使组件更灵活、更易复用。
一、什么是 Slot?
- 解决"结构固定、内容不确定"的场景
- 父组件可动态传入内容,提高复用性(如
Dialog、Select、Card)
二、三类插槽
1. 默认插槽(Default Slot)
子组件:
vue
<template>
<div class="card">
<slot></slot>
</div>
</template>
父组件:
vue
<Card>我是默认内容</Card>
2. 具名插槽(Named Slot)
子组件:
vue
<slot name="header" />
<slot />
<slot name="footer" />
父组件:
vue
<Card>
<template #header>标题</template>
默认内容
<template #footer>底部</template>
</Card>
3. 作用域插槽(Scoped Slot)
将子组件的数据传给父组件,由父组件决定如何渲染:
子组件:
vue
<slot :row="rowData"></slot>
父组件:
vue
<Child v-slot="{ row }">
<div>{{ row.name }}</div>
</Child>
表格组件(如 Element Plus、Ant Design Vue)的自定义列广泛使用作用域插槽。
三、运行原理(高频)
- 父组件的插槽内容在"父作用域"编译,但在子组件的
slot位置渲染 - 子组件只提供渲染占位;作用域始终属于父组件
示例:
vue
<Child>
{{ count }}
</Child>
上例中 count 来自父组件作用域,子组件无法修改父模板变量。
四、Slot 与 Props 的关系
Props:父 → 子(传值)Scoped Slot:子 → 父(传数据,父负责渲染)- 二者互补,
slot不能替代props
五、核心使用场景
- UI 组件扩展(
Dialog、Drawer)
vue
<Dialog>
<template #footer>
<button>确定</button>
</template>
</Dialog>
- 表格自定义列(作用域插槽)
vue
<el-table-column label="姓名">
<template #default="{ row }">
<b>{{ row.name }}</b>
</template>
</el-table-column>
- 动态模板注入(卡片、菜单、布局组件)
六、常见追问
-
追问 1:为什么父组件变量能在子组件 slot 中显示?
- 插槽内容在父作用域编译,渲染位置在子组件,但执行上下文仍属父组件
-
追问 2:
slot与scoped slot的本质区别?slot:父 → 子,父提供内容scoped slot:子 → 父,子提供数据,父决定渲染
-
追问 3:Vue3 中 slot 的编译结果?
- 默认插槽 →
$slots.default?.() - 具名插槽 →
$slots.header?.() - 作用域插槽 → 参数化渲染函数
(slotProps) => VNode
- 默认插槽 →
-
追问 4:
setup中如何访问 slot?
js
import { useSlots } from 'vue'
const slots = useSlots()
slots.default?.()
slots.header?.()
- 追问 5:slot 是否可动态调用?
vue
<component :is="slots[name]"></component>
在 Vue3 中,插槽本质上是函数。
七、一句话总结
编译在父、渲染在子、作用域属于父。
Slot是父模板注入;Scoped Slot用于子 → 父的数据回传。