插槽(Slot)是 Vue 组件中用于内容分发的占位机制。它允许你在父组件中向子组件的指定位置插入任意的模板内容,让组件从“封闭的盒子”变成“可定制的容器”。比如一个弹窗组件,它的标题、正文和按钮应该由使用者决定,但弹窗的遮罩层、关闭逻辑这些公共部分应该封装在组件内部。插槽就是为这种场景而生的。
默认插槽
默认插槽是最简单的插槽形式。子组件中放置一个 <slot></slot> 标签作为占位,父组件在使用该组件时,在标签体中写入的任何内容都会渲染到这个位置。
子组件 MyCard.vue
<template>
<div class="card">
<div class="card-header">固定标题</div>
<div class="card-body">
<slot></slot> <!-- 插槽出口,父组件的内容会出现在这里 -->
</div>
<div class="card-footer">固定页脚</div>
</div>
</template>
父组件中使用
<template>
<MyCard>
<p>这是插入到卡片主体中的自定义内容。</p>
<button>操作按钮</button>
</MyCard>
</template>
子组件中的 <slot> 就像一个“空位”,父组件中写的内容正好“填入”这个空位。如果父组件没有传任何内容,<slot></slot> 处会显示它自己的后备内容(可以写在 <slot> 标签内,比如 <slot>默认文本</slot>)。
具名插槽
当组件需要多个可替换的区域时,默认插槽就不够用了。具名插槽允许你给每个插槽定义一个 name 属性,父组件通过 v-slot:名称 或者语法糖 #名称 将内容分发到指定的插槽。
子组件 MyLayout.vue
<template>
<div class="layout">
<header>
<slot name="header"></slot> <!-- 名为 header 的插槽 -->
</header>
<main>
<slot></slot> <!-- 默认插槽,等价于 name="default" -->
</main>
<footer>
<slot name="footer"></slot> <!-- 名为 footer 的插槽 -->
</footer>
</div>
</template>
父组件中使用
<template>
<MyLayout>
<!-- 具名插槽用 v-slot:header 或简写 #header -->
<template #header>
<h1>页面标题</h1>
</template>
<!-- 默认插槽的内容可以直接写在组件标签内,或者用 #default 明确指定 -->
<p>主要内容区域...</p>
<template #footer>
<small>版权信息 © 2025</small>
</template>
</MyLayout>
</template>
注意,只有在 <template> 元素上才能使用 v-slot 指令的简写 #,非 <template> 标签上必须写成 v-slot:名称。如果组件中只有一个默认插槽,父组件的非具名内容都会自动归入这个默认插槽,无需包裹 <template>。
实际场景举例:一个 Dialog 组件,头部、正文、底部按钮都可以自定义,但遮罩层和布局结构由组件内部管理,这就是典型的具名插槽用例。
总结
- 默认插槽:子组件用
<slot />,父组件直接往标签里塞内容。 - 具名插槽:子组件用
<slot name="xxx">,父组件用<template #xxx>或v-slot:xxx分配内容。
插槽让组件拥有了“开放封闭原则”的能力——对内封装不变的结构和逻辑,对外暴露可定制的部分,是构建可复用组件库的基础。