插槽的定义
1、组件中默认插槽的定义:
<a :href="url">
<slot></slot>
</a>
2、具名插槽的定义:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
插槽的使用
1、默认插槽的使用
<navigation-link url="/profile">
Your Profile
</navigation-link>
2、具名插槽的使用
<!-- vue2.6.0之前 -->
<base-layout>
<template slot="header">
<h1>Here might be a page title</h1>
</template>
<!-- 隐藏默认插槽 slot="default" -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template slot="footer">
<p>Here's some contact info</p>
</template>
</base-layout>
<!-- vue2.6.0之后(包括vue3) -->
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<!-- 隐藏默认插槽 v-slot:default -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
注意:v-slot 只能添加在
<template>
上,(例外:当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。) 但是,slot-scope 可以直接用于非<template>
元素 (包括组件)。
例如:
<current-user v-slot="slotProps">
</current-user>
<slot-example>
<span slot-scope="slotProps">
</span>
</slot-example>
作用域插槽
在插槽中,如果想使用定义插槽的组件的数据:
比如current-user组件,
<span>
<slot></slot>
</span>
我们可能想换掉备用内容,用名而非姓来显示。如下:
<current-user>
</current-user>
我们需要在插槽内容将user暴露出来:
<span>
<slot :user="user">
</slot>
</span>
然后才能使用:
<!-- vue2.6.0之前 -->
<current-user>
<template slot-scope="slotProps">
</template>
</current-user>
<!-- vue2.6.0之后(包括vue3) -->
<current-user>
<template v-slot="slotProps">
</template>
</current-user>
当然,我们也可以采用解构赋值
和重命名
的写法:
<!-- 解构赋值 -->
<current-user v-slot="{ user }">
</current-user>
<!-- 解构赋值+重命名 -->
<current-user v-slot="{ user: person }">
</current-user>
<!-- 解构赋值+插槽默认值 -->
<current-user v-slot="{ user = { firstName: 'daotin' } }">
</current-user>
当然,v-slot也可以采用缩写
的写法:
跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header:
<!-- 注意:#="{ user } 会触发一个警告 -->
<current-user #default="{ user }">
</current-user>
$slots 和 $scopedSlots
1、$slots
一个表示父组件所传入插槽的对象。通常用于手写render渲染函数,但也可用于检测是否存在插槽。
可以直接通过 $slots.slotName
访问对应的插槽内容,其中 slotName
是插槽的名字。如果插槽是默认插槽(无名字),则通过 $slots.default
访问。
2、$scopedSlots
: 作用域插槽允许子组件将数据传递到它的插槽内容中,这些内容是由父组件提供的。这种机制允许父组件访问到从子组件传来的数据,以便根据这些数据动态渲染插槽内容。
使用和目的:
-
子组件定义作用域插槽: 子组件通过
slot
标签定义一个插槽,并通过v-bind
或简写:
将数据传递到插槽中。这就创建了一个作用域插槽,子组件通过这种方式向外暴露数据。 -
父组件使用作用域插槽: 父组件在使用子组件时,通过
<template v-slot:slotName="slotProps">
的方式接收这些数据。在这里,slotName
是子组件定义的插槽名,slotProps
是一个对象,包含了子组件传递的所有数据。 -
为什么使用
$scopedSlots.slotName
:- 在子组件中:如果子组件需要检查父组件是否提供了特定的作用域插槽,或者需要以编程方式访问作用域插槽的内容(例如在 render 函数中),可以使用
$scopedSlots.slotName
。这种方式可以访问到一个函数,该函数返回对应插槽的渲染结果(虚拟 DOM 节点)。 - 动态内容渲染:在某些情况下,子组件可能需要根据是否存在某个作用域插槽来改变其自身的渲染逻辑。
- 在子组件中:如果子组件需要检查父组件是否提供了特定的作用域插槽,或者需要以编程方式访问作用域插槽的内容(例如在 render 函数中),可以使用
示例:
<!-- ParentComponent.vue -->
<template>
<UserCard>
<!-- 默认插槽 -->
<template v-slot:default>
<p>Welcome to the user card!</p>
</template>
<!-- 具名插槽 -->
<template v-slot:header>
<h1>User Information</h1>
</template>
<!-- 作用域插槽 -->
<template v-slot:details="slotProps">
<p>Name: </p>
<p>Email: </p>
</template>
</UserCard>
</template>
<script>
import UserCard from './UserCard.vue';
export default {
components: {
UserCard
}
}
</script>
<!-- UserCard.vue -->
<template>
<div>
<div v-if="$scopedSlots.header">
<!-- 只有在父组件提供了header插槽时才渲染 -->
<slot name="header"></slot>
</div>
<div>
<!-- 总是渲染默认插槽 -->
<slot></slot>
</div>
<div v-if="$scopedSlots.details">
<!-- 只有在父组件提供了details插槽时才渲染 -->
<slot name="details" :user="user"></slot>
</div>
</div>
</template>
<script>
export default {
data() {
return {
user: {
name: 'John Doe',
email: 'john@example.com'
}
};
},
mounted() {
// 访问默认插槽内容
console.log(this.$slots.default); // 包含 <template> 标签中的内容:VNode数组
// 访问具名插槽内容
console.log(this.$slots.header); // 包含 <h1>User Information</h1>:VNode数组
// 访问作用域插槽内容
const scopedSlotContent = this.$scopedSlots.details({ user: this.user });
console.log(scopedSlotContent); // // VNode数组,包含作用域插槽 'details' 的内容
}
}
</script>