🧩 一、什么是插槽(Slot)
插槽(Slot) 是 Vue 中的一个非常强大的特性,用于在 组件之间传递结构化内容。
简而言之:
插槽就是 "占位符",父组件可以在这个占位符中插入任意模板内容。
🧱 二、插槽的三种类型
Vue 3 中主要有三类插槽:
-
默认插槽(Default Slot)
-
具名插槽(Named Slot)
-
作用域插槽(Scoped Slot)
🧭 三、默认插槽(Default Slot)
🔹 子组件定义插槽
html
<!-- Child.vue -->
<template>
<div class="child">
<h3>我是子组件</h3>
<slot></slot> <!-- 插槽占位 -->
</div>
</template>
🔹 父组件传入内容
html
<!-- Parent.vue -->
<template>
<Child>
<p>这是插入到默认插槽的内容。</p>
</Child>
</template>
🔹 渲染结果
html
<div class="child">
<h3>我是子组件</h3>
<p>这是插入到默认插槽的内容。</p>
</div>
如果父组件没有传入任何内容,Vue 会使用 默认内容:
html
<slot>这里是默认内容</slot>
🏷️ 四、具名插槽(Named Slot)
当一个组件有多个插槽时,就需要用名字来区分。
🔹 子组件定义
html
<!-- Child.vue -->
<template>
<header>
<slot name="header">默认头部</slot>
</header>
<main>
<slot>默认主体</slot>
</main>
<footer>
<slot name="footer">默认底部</slot>
</footer>
</template>
🔹 父组件传入
html
<template>
<LayoutComponent>
<!-- Vue 3 语法:使用 v-slot 指令 -->
<template v-slot:header>
<h1>网站标题</h1>
<nav>导航菜单</nav>
</template>
<template v-slot:content>
<article>
<h2>文章标题</h2>
<p>文章内容...</p>
</article>
</template>
<template v-slot:sidebar>
<div class="sidebar">
<h3>侧边栏</h3>
<ul>
<li>链接1</li>
<li>链接2</li>
</ul>
</div>
</template>
<template v-slot:footer>
<p>版权信息 © 2023</p>
</template>
</LayoutComponent>
</template>
💡 注意:
#header是v-slot:header的语法糖。默认插槽用
#default或直接写内容。
🧮 五、作用域插槽(Scoped Slot)
作用域插槽允许子组件 向父组件传递数据。
🔹 子组件提供数据
html
<!-- Child.vue -->
<template>
<ul>
<slot :items="list"></slot>
</ul>
</template>
<script setup>
const list = ['苹果', '香蕉', '橘子']
</script>
🔹 父组件使用插槽并接收数据
html
<!-- Parent.vue -->
<template>
<Child v-slot="{ items }">
<li v-for="(item, i) in items" :key="i">{{ i + 1 }} - {{ item }}</li>
</Child>
</template>
渲染结果:
html
<ul>
<li>1 - 苹果</li>
<li>2 - 香蕉</li>
<li>3 - 橘子</li>
</ul>
💡 说明
-
子组件通过
slot标签上的属性向父组件 暴露数据; -
父组件使用
v-slot="{ ... }"解构这些数据; -
这就是"作用域插槽":父组件可以访问子组件提供的"插槽上下文"。
🧱 六、v-slot 完整语法总结
| 语法形式 | 用法说明 |
|---|---|
<template v-slot:header> |
具名插槽 |
<template #header> |
具名插槽(语法糖) |
<template v-slot:default> |
默认插槽 |
<template #default> |
默认插槽(语法糖) |
<Child v-slot="{ data }"> |
作用域插槽 |
<Child #default="{ data }"> |
作用域插槽语法糖 |
🧠 七、插槽底层原理(简述)
Vue 的插槽在编译阶段会被转换成渲染函数(render function)的一部分:
-
子组件模板中的
<slot>会生成一个 slot 函数调用; -
父组件传入的
<template v-slot>会被编译为一个 函数; -
渲染时,Vue 会把父组件提供的函数传递给子组件,子组件在执行时调用它,形成一种 内容分发机制。
所以插槽本质上是:
"通过函数传递模板内容" 的机制。
⚙️ 八、综合示例
html
<!-- Card.vue -->
<template>
<div class="card">
<header><slot name="header">默认标题</slot></header>
<main><slot :info="info"></slot></main>
<footer><slot name="footer">默认页脚</slot></footer>
</div>
</template>
<script setup>
const info = { author: 'smatter er', date: '2025-10-30' }
</script>
html
<!-- App.vue -->
<template>
<Card>
<template #header>
<h2>文章标题</h2>
</template>
<template #default="{ info }">
<p>作者:{{ info.author }},日期:{{ info.date }}</p>
</template>
<template #footer>
<button>阅读全文</button>
</template>
</Card>
</template>
渲染结果:
html
<div class="card">
<header><h2>文章标题</h2></header>
<main><p>作者:smatter er,日期:2025-10-30</p></main>
<footer><button>阅读全文</button></footer>
</div>
🧩 九、插槽的使用建议
✅ 适用场景:
-
通用组件(如卡片、弹窗、表格);
-
灵活布局(header、footer、sidebar);
-
组件内动态内容插入。
⚠️ 注意事项:
-
插槽内容在父组件作用域中编译;
-
子组件只能通过作用域插槽提供数据;
-
避免滥用插槽导致组件复杂化。