Vue3中具名插槽的使用方式更加统一和简洁。
新版本采用v-slot指令(简写为#)替代Vue2的slot和slot-scope属性,支持默认插槽、具名插槽和作用域插槽。
子组件通过name属性定义插槽,父组件使用#插槽名语法插入内容。
Vue3还增强了动态插槽名支持和参数解构功能,废弃了旧语法,使插槽使用更加一致,特别是在TypeScript环境下提供更好的类型推断。
Vue 3 中的具名插槽仍然完全支持,而且语法更加统一和一致。
以下是 Vue 3 中具名插槽的使用方式:
1. 基础具名插槽使用
子组件:BaseLayout.vue
vue
<template>
<div class="container">
<header>
<!-- 具名插槽:header -->
<slot name="header"></slot>
</header>
<main>
<!-- 默认插槽 -->
<slot></slot>
<!-- 或者明确指定默认插槽 -->
<slot name="default"></slot>
</main>
<footer>
<!-- 具名插槽:footer -->
<slot name="footer"></slot>
</footer>
</div>
</template>
父组件使用:
vue
<template>
<BaseLayout>
<!-- Vue 3 的新语法:v-slot 指令 -->
<template v-slot:header>
<h1>这里是页头</h1>
</template>
<!-- 默认插槽内容(两种写法都可以) -->
<p>这里是主要内容</p>
<!-- 或者明确指定默认插槽 -->
<template v-slot:default>
<p>这里是主要内容</p>
</template>
<!-- 具名插槽:footer -->
<template v-slot:footer>
<p>这里是页脚</p>
</template>
</BaseLayout>
</template>
2. 简写语法(推荐)
Vue 3 推荐使用简写语法 #:
vue
<template>
<BaseLayout>
<!-- 简写:使用 # 代替 v-slot: -->
<template #header>
<h1>这里是页头</h1>
</template>
<!-- 默认插槽的简写 -->
<p>这里是主要内容</p>
<!-- 或者 -->
<template #default>
<p>这里是主要内容</p>
</template>
<template #footer>
<p>这里是页脚</p>
</template>
</BaseLayout>
</template>
3. 作用域插槽(带参数的插槽)
子组件:CurrentUser.vue
vue
<template>
<slot name="default" :user="user" :age="age"></slot>
<!-- 或者具名作用域插槽 -->
<slot name="info" :user="user" :age="age"></slot>
</template>
<script setup>
import { ref } from 'vue'
const user = ref('张三')
const age = ref(25)
</script>
父组件接收插槽参数:
vue
<template>
<CurrentUser>
<!-- 接收默认插槽的参数 -->
<template v-slot:default="slotProps">
<p>用户:{{ slotProps.user }},年龄:{{ slotProps.age }}</p>
</template>
<!-- 具名作用域插槽 -->
<template #info="{ user, age }">
<p>信息:{{ user }}({{ age }}岁)</p>
</template>
</CurrentUser>
</template>
4. 动态插槽名
vue
<template>
<BaseLayout>
<template #[dynamicSlotName]>
<p>动态插槽内容</p>
</template>
<!-- 使用动态插槽名 -->
<template v-slot:[headerSlot]>
<h1>动态页头</h1>
</template>
</BaseLayout>
</template>
<script setup>
import { ref } from 'vue'
const dynamicSlotName = ref('header')
const headerSlot = ref('header')
</script>
5. 多个插槽的简写和解构
vue
<template>
<TodoList :todos="todos">
<!-- 解构插槽参数并使用重命名 -->
<template #default="{ item: todo, index }">
<div class="todo-item">
<span>{{ index + 1 }}. {{ todo.text }}</span>
<span v-if="todo.completed">✓</span>
</div>
</template>
</TodoList>
</template>
<script setup>
import { ref } from 'vue'
const todos = ref([
{ text: '学习 Vue 3', completed: true },
{ text: '学习 TypeScript', completed: false }
])
</script>
6. 与 Vue 2 的对比
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 语法 | slot="name" |
v-slot:name 或 #name |
| 作用域插槽 | slot-scope |
v-slot 统一处理 |
| 默认插槽 | 匿名内容 | #default 或匿名内容 |
| 动态插槽名 | 有限支持 | 完全支持 |
Vue 2 的旧语法(Vue 3 中已废弃):
vue
<!-- Vue 2 旧语法(Vue 3 中不支持) -->
<BaseLayout>
<template slot="header">
<h1>页头</h1>
</template>
<p slot="default">内容</p>
<template slot="footer" slot-scope="props">
<p>页脚 {{ props.data }}</p>
</template>
</BaseLayout>
7. 注意事项
-
废弃的语法 :
slot和slot-scope属性在 Vue 3 中已废弃 -
v-slot 只能用于
<template>:不能直接用在普通元素上 -
默认插槽的两种写法:
vue
<!-- 写法1:匿名内容 --> <Child>默认内容</Child> <!-- 写法2:明确指定 --> <Child> <template #default> 默认内容 </template> </Child>
总结
Vue 3 没有废弃具名插槽,而是:
-
统一了语法 :使用
v-slot指令处理所有插槽 -
提供了简写 :
#符号 -
增强了功能:更好的类型支持和动态插槽
-
废弃了旧语法 :移除了
slot和slot-scope属性
这种改变让插槽语法更加一致和强大,特别是在使用 TypeScript 时提供更好的类型推断。