目标:掌握组件内容分发的灵活方式
1. 默认插槽(匿名插槽)
html
<!-- 子组件 Layout.vue -->
<template>
<div class="container">
<header>
<slot></slot> <!-- 内容插入点 -->
</header>
</div>
</template>
<!-- 父组件使用 -->
<Layout>
<h1>这是插入的标题内容</h1>
</Layout>
关键点:
-
<slot>
标签定义内容占位符 -
父组件传入的内容会替换子组件的
<slot>
2. 具名插槽
html
<!-- 子组件 Card.vue -->
<template>
<div class="card">
<slot name="header"></slot>
<slot name="content"></slot>
<slot name="footer"></slot>
</div>
</template>
<!-- 父组件使用 -->
<Card>
<template v-slot:header>
<h2>卡片标题</h2>
</template>
<template #content> <!-- 简写语法 -->
<p>卡片正文内容...</p>
</template>
<template #footer>
<button>确认</button>
</template>
</Card>
语法说明:
-
v-slot:name
或简写#name
指定插槽名称 -
未命名的
<template>
内容会填充到默认插槽
3. 作用域插槽(向父组件传递数据)
html
<!-- 子组件 TodoList.vue -->
<template>
<ul>
<li v-for="todo in todos" :key="todo.id">
<slot :todo="todo"></slot>
</li>
</ul>
</template>
<!-- 父组件使用 -->
<TodoList :todos="todoList">
<template #default="slotProps">
<span :class="{ done: slotProps.todo.isDone }">
{{ slotProps.todo.text }}
</span>
</template>
</TodoList>
关键点:
-
子组件通过
<slot :data="value">
传递数据 -
父组件通过
#slotName="props"
接收数据
4. 插槽默认内容
html
<!-- 子组件 Button.vue -->
<template>
<button class="btn">
<slot>提交</slot> <!-- 父组件不传内容时显示"提交" -->
</button>
</template>
5. 动态插槽名(Vue3新特性)
html
<template>
<Component>
<template #[dynamicSlotName]>
动态插槽内容
</template>
</Component>
</template>
<script setup>
const dynamicSlotName = ref('header')
</script>
6. 插槽实战场景
-
布局组件:定义页面的通用结构(Header/Content/Footer)
-
UI组件库:Table组件的自定义单元格渲染
-
高阶组件:通过作用域插槽传递业务数据
最佳实践:
-
复杂组件优先使用具名插槽
-
避免在插槽内容中直接修改子组件状态
-
作用域插槽适合需要定制渲染逻辑的场景