729 字
4 分钟
Vue 3 组件插槽

插槽是什么#

插槽是组件的内容分发机制。子组件在模板里放一个 <slot> 占位,父组件写在子组件标签里的内容就渲染到这个位置。

<!-- 子组件 Dialog.vue -->
<div class="dialog">
<slot></slot>
</div>

默认插槽#

<slot> 不写 name 时,它的名字隐含为 default,也就是默认插槽。

<Dialog>
<div>我是填充的内容</div>
</Dialog>

父组件标签里没有指定插槽名的顶层内容,都会进入默认插槽。

具名插槽#

子组件需要多个内容出口时,给每个 <slot> 起 name,父组件按名字填充。

<!-- 子组件 -->
<div>
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>

父组件用 <template v-slot:xxx> 指定目标插槽,v-slot:xxx 对应子组件里 name="xxx" 的插槽,简写是 #。没有指定名字的内容落在默认插槽。

<Dialog>
<template v-slot:header>
<div>我是头部</div>
</template>
<template v-slot:footer>
<div>我是底部</div>
</template>
<div>我是默认内容</div>
</Dialog>

v-slot 放在哪里#

v-slot 写在 <template> 上和写在组件上都行。写在组件上时,只支持单个默认作用域插槽:

<Mouse v-slot="{ x, y }">
Mouse position: {{ x }}, {{ y }}
</Mouse>

想同时用具名插槽和默认作用域插槽时,把 v-slot 放在组件上会编译报错,这时默认插槽要写成显式的 <template #default>。

v-slot 后面的参数可以省略,省略时指向 default,所以 <Child v-slot="{ x, y }"> 是合法的。只有要填充具名插槽时,才需要写名字。

作用域插槽#

普通插槽只能读父组件的数据。作用域插槽让子组件在渲染时把自己内部的数据传出去,由父组件决定怎么显示。

子组件在 <slot> 上用 v-bind 绑数据:

<!-- 子组件 -->
<slot :data="item"></slot>

这些绑定会打包成一个插槽 props 对象,父组件在 v-slot 的值上接收,可以直接解构:

<Dialog>
<template #default="{ data }">
<div>{{ data }}</div>
</template>
</Dialog>

#default="props" 拿到的是整个对象,写成 #default="{ data }" 就只取需要的字段。

列表、表格、树形这类组件常用作用域插槽:子组件负责遍历和取数,父组件负责每一项怎么显示。

动态插槽名#

插槽名可以是变量,用 #[slotName] 绑定:

<template>
<Dialog>
<template #[activeSlot]>
<div>插到 {{ activeSlot }} 插槽</div>
</template>
</Dialog>
</template>
<script setup>
import { ref } from 'vue'
const activeSlot = ref('header')
</script>

方括号里的表达式求值结果应当是字符串(也允许 null),否则匹配不到具名插槽。常见用法是按状态切换插槽。

插槽的默认内容#

<slot> 标签里的内容就是默认内容,父组件没有提供对应内容时显示:

<slot>
我是默认内容,父组件没填时显示
</slot>

第 15 篇,共 19 篇本文属于系列

Vue 3 组件插槽
https://www.choria.top/posts/vue3-slot/
作者
乔瑞雅·克林威尔
发布于
2026-04-14
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取

最后更新于 ,距今已过 208 天

部分内容可能已过时