📖 概述
useSlots()
是 Vue 3 中的一个组合式 API 辅助函数,用于在组件中访问插槽内容。defineSlots()
是 Vue 3.3+ 版本中引入的编译时宏,专门用于<script setup>
中的插槽类型定义和访问。
⚠️ 重要提示:如果使用 <script setup>
,应当优先使用 defineSlots()
。
🎯 基本概念
什么是 useSlots?
useSlots()
是一个运行时函数,用于在组件的 setup 函数中访问插槽内容。它返回一个包含所有插槽函数的对象,允许你以编程方式访问和操作插槽。
什么是 defineSlots?
defineSlots()
是一个编译时宏,专门用于<script setup>
中定义插槽的类型和访问插槽内容。它提供了更好的 TypeScript 支持和类型检查。
两者的关系
特性 | defineSlots() | useSlots() |
---|---|---|
使用场景 | <script setup> 语法糖 | 运行时函数 |
代码简洁度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
类型安全 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
推荐程度 | 应当优先使用 | 特定场景使用 |
- ✅
defineSlots()
是<script setup>
中的语法糖,提供更好的类型支持,应当优先使用 - 🔧
useSlots()
是运行时函数,适用于非单文件组件或需要动态访问插槽的场景
🔧 函数签名
defineSlots()
function defineSlots<
TSlots extends Record<string, any> = Record<string, any>
>(): TSlots;
useSlots()
function useSlots(): Slots;
📋 类型定义
type Slots = {
[key: string]: Slot | undefined;
};
type Slot = (...args: any[]) => VNode[];
🎯 使用场景
1️⃣ defineSlots 适用场景
在
<script setup>
中需要访问插槽内容时,defineSlots()
是最佳选择。
2️⃣ useSlots 适用场景
当使用传统的
setup()
函数而不是<script setup>
时,useSlots()
是访问插槽的唯一选择。
3️⃣ 动态插槽访问
当需要根据条件动态访问不同的插槽时,
useSlots()
提供了更大的灵活性。
💻 代码示例
🚀 defineSlots 基础用法
<script setup lang="ts">
const slots = defineSlots<{
default(props: { msg: string }): any;
header(): any;
footer(props: { year: number }): any;
}>();
// 检查插槽是否存在
if (slots.default) {
console.log("默认插槽存在");
}
// 访问插槽内容
const defaultContent = slots.default?.({ msg: "Hello" });
</script>
<template>
<div>
<!-- 使用插槽 -->
<slot name="header" />
<slot :msg="'Hello World'" />
<slot name="footer" :year="2024" />
</div>
</template>
🎨 列表渲染插槽
<script setup lang="ts">
// 定义 props
interface Props {
items: string[];
}
const props = defineProps<Props>();
// 定义插槽类型
interface Slots {
item(props: { item: string; index: number }): any;
}
// 使用 defineSlots 定义插槽
const slots = defineSlots<Slots>();
</script>
<template>
<div>
<!-- 循环渲染列表项 -->
<template v-for="(item, index) in items" :key="index">
<slot name="item" :item="item" :index="index" />
</template>
</div>
</template>
🔧 useSlots 基础用法
export default {
setup() {
const slots = useSlots();
// 检查插槽是否存在
if (slots.default) {
console.log("默认插槽存在");
}
// 动态访问插槽
const slotNames = Object.keys(slots);
console.log("可用插槽:", slotNames);
return {
slots,
};
},
};
⚖️ 与 useSlots 的对比
✅ defineSlots (推荐用于 script setup)
<script setup lang="ts">
const slots = defineSlots<{
default(): any;
header(): any;
}>();
// 类型安全的插槽访问
if (slots.header) {
// TypeScript 知道 header 插槽存在
}
</script>
🔧 useSlots (适用于 setup 函数)
export default {
setup() {
const slots = useSlots();
// 运行时插槽访问
if (slots.header) {
// 需要手动检查插槽是否存在
}
return { slots };
},
};
⚠️ 注意事项
🔢 版本要求
- 🚫
defineSlots()
仅在 Vue 3.3+ 版本中可用 - ✅
useSlots()
在 Vue 3.0+ 中可用 - ✅ 确保项目依赖版本满足要求
📝 类型安全
defineSlots()
提供了更好的 TypeScript 支持:
// 完整的类型定义
const slots = defineSlots<{
default(props: { title: string; count: number }): any;
header(props: { level: 1 | 2 | 3 }): any;
footer(): any;
}>();
// TypeScript 会提供完整的类型提示
slots.default?.({ title: "Hello", count: 42 });
slots.header?.({ level: 1 });
🛡️ 运行时检查
即使使用 defineSlots()
,仍然需要在运行时检查插槽是否存在:
<script setup>
const slots = defineSlots<{
header(): any
}>()
// 始终检查插槽是否存在
const hasHeader = computed(() => !!slots.header)
</script>
<template>
<div>
<header v-if="hasHeader">
<slot name="header" />
</header>
</div>
</template>
🎯 最佳实践
1️⃣ 优先使用 defineSlots
在
<script setup>
中,应当优先使用defineSlots()
,提供更好的类型支持和开发体验。 只有在以下情况下才考虑使用useSlots()
:
- 🔧 使用传统的
setup()
函数 - ⚙️ 需要动态访问插槽名称
- 🎛️ 需要更复杂的插槽操作逻辑
2️⃣ 合理使用类型定义
为插槽提供完整的类型定义,提高代码的可维护性:
const slots = defineSlots<{
default(props: { message: string }): any;
header(props: { title: string; subtitle?: string }): any;
footer(): any;
}>();
3️⃣ 避免过度使用
插槽主要用于内容分发,避免在 setup 中过度操作插槽内容。
❓ 常见问题
Q: 什么时候使用 useSlots 而不是 defineSlots?
A: 在
<script setup>
中,应当优先使用defineSlots()
。 只有在以下情况下才使用useSlots()
:
- 🔧 使用传统的
setup()
函数而不是<script setup>
- ⚙️ 需要动态访问插槽名称(如
slots[slotName]
) - 🎛️ 需要更复杂的插槽操作逻辑
Q: defineSlots 是否支持动态插槽名称?
A:
defineSlots()
主要用于静态类型定义,对于动态插槽名称,建议使用useSlots()
。
Q: 如何处理插槽的默认值?
A: 可以在模板中使用插槽的默认内容,或在 setup 中提供默认值:
<template>
<slot name="header">
<h1>默认标题</h1>
</slot>
</template>
Q: defineSlots 的类型参数是否必需?
A: 不是必需的,但强烈建议提供类型定义以获得更好的 TypeScript 支持。
📝 总结
defineSlots()
和useSlots()
都是 Vue 3 中访问插槽内容的有效方式。重要原则:在<script setup>
中,应当优先使用defineSlots()
,提供更好的类型支持和开发体验。 只有在使用传统的setup()
函数或需要动态插槽访问时,才考虑使用useSlots()
。理解这两个 API 的使用场景和差异,有助于在 Vue 3 项目中更好地管理组件插槽。
评论0