在 Vue 2 和 Vue 3 中,插槽(Slot)是组件间传递内容的重要机制,用于实现组件的灵活复用。两者在插槽的基本概念上一致,但在语法细节、具名插槽用法、作用域插槽(插槽传参)的写法上存在明显差异。
一、默认插槽(匿名插槽)
默认插槽是最基础的插槽,用于传递无名称的内容。
Vue 2 用法:
- 子组件中用
<slot></slot>
定义插槽出口 - 父组件中直接在子组件标签内写入内容,会被分发到默认插槽
vue
<!-- 子组件 Child.vue -->
<template>
<div class="child">
<h3>子组件标题</h3>
<slot></slot>
<!-- 插槽出口 -->
</div>
</template>
<!-- 父组件 Parent.vue -->
<template>
<div class="parent">
<Child>
<!-- 插槽内容会被插入到子组件的 slot 位置 -->
<p>这是默认插槽的内容</p>
</Child>
</div>
</template>
Vue 3 用法:
基本用法与 Vue 2 一致,但 Vue 3 对插槽的解析更严格,推荐显式使用 <template>
包裹(非必须)。
vue
<!-- 子组件 Child.vue -->
<template>
<div class="child">
<h3>子组件标题</h3>
<slot></slot>
<!-- 插槽出口 -->
</div>
</template>
<!-- 父组件 Parent.vue -->
<template>
<div class="parent">
<Child>
<!-- 内容直接放入,或用 template 包裹 -->
<template>
<p>这是 Vue 3 默认插槽的内容</p>
</template>
</Child>
</div>
</template>
二、具名插槽(Named Slots)
当组件需要多个插槽时,用名称区分不同插槽,称为具名插槽。
Vue 2 用法:
- 子组件中用
name
属性定义具名插槽:<slot name="header"></slot>
- 父组件中用
slot
属性指定内容对应的插槽名称:<p slot="header">...</p>
vue
<!-- 子组件 Child.vue -->
<template>
<div class="child">
<slot name="header"></slot>
<!-- 头部插槽 -->
<slot></slot>
<!-- 默认插槽(name 默认为 "default") -->
<slot name="footer"></slot>
<!-- 底部插槽 -->
</div>
</template>
<!-- 父组件 Parent.vue -->
<template>
<Child>
<!-- 用 slot 属性指定插槽名称 -->
<h1 slot="header">这是头部内容</h1>
<p>这是默认插槽内容</p>
<p slot="footer">这是底部内容</p>
</Child>
</template>
Vue 3 用法:
- 子组件定义方式不变:
<slot name="header"></slot>
- 父组件中必须用
<template>
配合v-slot
指令 ,格式为v-slot:插槽名
(可简写为#插槽名
)
vue
<!-- 子组件 Child.vue -->
<template>
<div class="child">
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
</div>
</template>
<!-- 父组件 Parent.vue -->
<template>
<Child>
<!-- 具名插槽:v-slot:header 可简写为 #header -->
<template #header>
<h1>这是头部内容</h1>
</template>
<!-- 默认插槽:v-slot:default 可简写为 #default 或省略 -->
<template #default>
<p>这是默认插槽内容</p>
</template>
<template #footer>
<p>这是底部内容</p>
</template>
</Child>
</template>
Vue 3 变化核心 :废弃 slot
属性,统一用 v-slot
指令,且必须配合 <template>
使用(默认插槽可省略 <template>
,直接写内容)。
三、作用域插槽(插槽传参)
子组件向父组件的插槽内容传递数据(子传父),称为作用域插槽(即插槽传参)。
Vue 2 用法:
- 子组件中通过
slot-scope
属性绑定数据:<slot :user="user" :age="18"></slot>
- 父组件中用
slot-scope
接收数据(可在标签或<template>
上)
vue
<!-- 子组件 Child.vue -->
<template>
<div class="child">
<!-- 向插槽传递数据:user 和 age -->
<slot name="content" :user="user" :age="18"></slot>
</div>
</template>
<script>
export default {
data() {
return {
user: { name: "张三", gender: "男" },
};
},
};
</script>
<!-- 父组件 Parent.vue -->
<template>
<Child>
<!-- 用 slot-scope 接收子组件传递的数据(对象形式) -->
<template slot="content" slot-scope="slotProps">
<p>姓名:{{ slotProps.user.name }}</p>
<p>年龄:{{ slotProps.age }}</p>
</template>
</Child>
</template>
slotProps
是接收数据的变量名(可自定义),包含子组件传递的所有数据- 也可直接解构:
slot-scope="{ user, age }"
Vue 3 用法:
- 子组件传递数据的方式不变:
<slot :user="user" :age="18"></slot>
- 父组件中用
v-slot:插槽名="接收变量"
接收(可简写为#插槽名="接收变量"
)
vue
<!-- 子组件 Child.vue -->
<template>
<div class="child">
<slot name="content" :user="user" :age="18"></slot>
</div>
</template>
<script setup>
import { reactive } from "vue";
const user = reactive({ name: "张三", gender: "男" });
</script>
<!-- 父组件 Parent.vue -->
<template>
<Child>
<!-- 用 #content="slotProps" 接收数据 -->
<template #content="slotProps">
<p>姓名:{{ slotProps.user.name }}</p>
<p>年龄:{{ slotProps.age }}</p>
</template>
<!-- 也可直接解构 -->
<template #content="{ user, age }">
<p>姓名:{{ user.name }}</p>
<p>年龄:{{ age }}</p>
</template>
</Child>
</template>
Vue 3 变化核心 :废弃 slot-scope
属性,统一用 v-slot
指令接收数据,写法更统一。
总结:Vue 2 vs Vue 3 插槽用法区别
类型 | Vue 2 语法 | Vue 3 语法 | 核心变化 |
---|---|---|---|
具名插槽 | 用 slot="名称" 属性 |
用 <template v-slot:名称> 或 #名称 |
废弃 slot 属性,改用 v-slot |
作用域插槽 | 用 slot-scope 接收数据 |
用 v-slot:名称="变量" 接收数据 |
废弃 slot-scope ,合并到 v-slot |
默认插槽 | 直接写内容或 slot="default" |
直接写内容或 #default |
语法更简洁,推荐显式 <template> |
注意 :Vue 3 对插槽语法做了标准化,更强调结构化和一致性,同时保持了核心功能不变。迁移时需注意将 slot
属性和 slot-scope
替换为 v-slot
指令。