Vue3插槽的使用方式与Vue2类似,但结合组合式API后有了更灵活的实现。以下是核心用法及示例:
一、默认插槽
在子组件中通过 <slot></slot> 定义默认插槽,父组件通过标签包裹内容插入:
<!-- 子组件 Child.vue -->
<div>
<slot>默认内容(当父组件未传内容时显示)</slot>
</div>
<!-- 父组件使用 -->
<Child>
<p>自定义内容</p>
</Child>
二、具名插槽
通过 name 属性定义多个插槽区域:
<!-- 子组件 -->
<div>
<slot name="header"></slot>
<slot name="content"></slot>
</div>
父组件通过 <slot> 标签指定名称插入:
<Child>
<template #header>
<h1>标题</h1>
</template>
<template #content>
<p>正文内容</p>
</template>
</Child>
三、作用域插槽(动态数据传递)
子组件通过 $emit 或 v-slot 传递数据给父组件插槽:
<!-- 子组件 -->
<div>
<slot name="item" :user="user"></slot>
</div>
父组件接收数据:
<Child>
<template #item="{ user }">
<div>{{ user.name }} - {{ user.age }}</div>
</template>
</Child>
四、动态插槽
结合 v-if/v-for 动态控制插槽内容:
<Child>
<template v-if="showHeader" #header>
<h1>动态标题</h1>
</template>
</Child>
五、组合式API中的插槽处理
-
在
setup()中通过defineSlots()显式声明插槽结构,主要用于在<script setup>语法中为组件的插槽提供类型定义,能让ts在父组件中使用插槽时提供类型提示和校验。 -
defineSlots()纯粹是为了类型检查而存在的,编译后的代码中,这个函数会被移除,所以不会增加运行时的开销
使用示例:
//子组件
<script setup lang="ts">
// 子组件:声明插槽类型
const slots = defineSlots<{
default: (props: { id: number; text: string }) => any; //any不是强制要求,只是占位符表示允许返回任何值;核心类型安全在于作用域参数的定义,而非返回值类型
title?: () => any; // 可选的具名插槽
}>();
</script>
<template>
<!-- 使用插槽 -->
<slot :id="1" text="Hello" />
<slot name="title" />
</template>
//在父组件中使用时,ts会检查作用域参数的类型:
<template>
<Child>
<!-- 作用域参数 `id` 和 `text` 的类型会被自动推断 -->
<template #default="{ id, text }">{{ id }} - {{ text }}</template>
<template #title>标题</template>
</Child>
</template>
总结
Vue3插槽的核心逻辑与Vue2保持一致,但通过组合式API增强了类型安全和代码组织能力。