Vue3 插槽 的核心概念
Vue3 插槽
Vue3 插槽 的基础语法
默认插槽
<!-- 父组件 -->
<template>
<MyComponent>
<p>这是插入到默认插槽的内容</p>
</MyComponent>
</template>
<!-- 子组件 MyComponent.vue -->
<template>
<div class="container">
<slot>默认内容</slot> <!-- 无内容时显示默认文本 -->
</div>
</template>
具名插槽
<!-- 父组件 -->
<template>
<Layout>
<template #header>
<h1>页面标题</h1>
</template>
<template #default>
<p>主内容区域</p>
</template>
<template #footer>
<p>页脚信息</p>
</template>
</Layout>
</template>
<!-- 子组件 Layout.vue -->
<template>
<div class="layout">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot> <!-- 默认插槽 -->
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
作用域插槽
<!-- 子组件 Table.vue -->
<template>
<table>
<tr>
<slot name="row" v-for="item in items" :row="item">
<!-- 默认行模板 -->
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
</slot>
</tr>
</table>
</template>
<!-- 父组件使用 -->
<template>
<Table :items="dataList">
<template #row="{ row }">
<td class="custom-id">{{ row.id }}</td>
<td class="custom-name">{{ row.name.toUpperCase() }}</td>
</template>
</Table>
</template>
Vue3 插槽 的进阶特性
| 插槽类型 | 传递方式 | 适用场景 | 示例语法 |
|---|---|---|---|
| 默认插槽 | 直接传递HTML内容 | 基础内容注入 | <MyComponent>内容</MyComponent> |
| 具名插槽 | 使用 #slotName 语法 |
页面布局划分 | <template #header> |
| 作用域插槽 | 通过 :slotProp 传递数据 |
动态数据展示 | #row="{ item }" |
| 传参插槽 | v-slot:slotName="data" |
复杂数据处理 | v-slot:custom="props" |
动态插槽命名
<template>
<DynamicComponent>
<!-- 通过变量控制插槽名称 -->
<template [v-slot:dynamicName]="data">
<p>动态绑定的插槽内容:{{ data.value }}</p>
</template>
</DynamicComponent>
</template>
插槽内容作用域
<!-- 子组件传递数据 -->
<template>
<div>
<slot :count="100" :text="欢迎使用">
<!-- 默认内容 -->
</slot>
</div>
</template>
<!-- 父组件接收数据 -->
<template>
<ChildComponent>
<template v-slot="{ count, text }">
<p>{{ text }}, 当前计数:{{ count }}</p>
</template>
</ChildComponent>
</template>
Vue3 插槽 的实战应用
复用性导航栏组件
<!-- 导航栏组件 Navigation.vue -->
<template>
<nav>
<slot name="logo" :logo="appLogo" />
<slot name="menu" :items="menuItems" />
<slot name="actions" />
</nav>
</template>
<!-- 页面A使用 -->
<template>
<Navigation>
<template #logo="{ logo }">
<img :src="logo.url" alt="Logo" width="100" />
</template>
<template #menu="{ items }">
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
</template>
<template #actions>
<button>登录</button>
</template>
</Navigation>
</template>
动态内容对话框
<!-- Dialog.vue -->
<template>
<div class="dialog">
<header>
<slot name="title" default="默认标题" />
</header>
<main>
<slot />
</main>
<footer>
<slot name="footer" :close="closeDialog">
<button @click="closeDialog">关闭</button>
</slot>
</footer>
</div>
</template>
<!-- 使用示例 -->
<template>
<Dialog :title="自定义标题">
<p>这是对话框主体内容</p>
<template #footer="{ close }">
<button @click="close">确认</button>
<button @click="close">取消</button>
</template>
</Dialog>
</template>
Vue3 插槽 的注意事项
- 插槽位置混乱:避免将插槽内容放在错误的HTML结构层级中
- 作用域混淆:作用域插槽传递的props与组件内部变量冲突时,优先使用解构命名
- 默认内容失效:当父组件传递空内容时,子组件默认内容才会显示
- 具名插槽覆盖:多个同名插槽定义时,仅最后一个会生效
代码示例中展示了默认插槽、具名插槽和作用域插槽的典型用法。通过<slot>标签配合v-slot指令,可以实现灵活的组件内容定制。实际开发中建议为插槽设置清晰的命名规范,避免将业务逻辑混杂在插槽内容中。