20、Vue 3 (2024 版)基础笔记 - 插槽 Slots
我们已经了解到组件能够接收任意类型的 JavaScript 值作为 props,但组件要如何接收模板内容呢?在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。
<slot>
元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。
插槽的基础使用
1、创建插槽组件
src/components/slots/BaseSlot.vue
<template>
<div>
<h3>插槽的基础使用</h3>
<!-- 显示插槽内容 -->
<slot></slot>
</div>
</template>
<script setup lang="ts"></script>
2、父组件引入子组件
src/App.vue
<template>
<BaseSlot>
<div>
<p>父组件传递的数据</p>
<main>
<p>插槽内容</p>
</main>
</div>
</BaseSlot>
</template>
<script setup lang="ts">
import BaseSlot from "./components/slots/BaseSlot.vue"
</script>
插槽渲染作用域
如果有动态数据,那么这个动态数据是在子组件中进行渲染,还是在父组件中进行渲染?官方是这样说的:"插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。"
答案:在父组件中进行渲染。
1、父组件
src/App.vue
<template>
<BaseSlot>
<div>
<p>父组件传递的数据</p>
<main>
<ul>
<li v-for="article in articles" :key="article.id">{{ article.title }}</li>
</ul>
</main>
</div>
</BaseSlot>
</template>
<script setup lang="ts">
import {ref} from "vue"
import BaseSlot from "./components/slots/BaseSlot.vue"
const articles = ref([
{id:1, title:"我的世界真奇妙"},
{id:2, title:"王美丽呀"}
])
</script>
2、子组件
src/components/slots/BaseSlot.vue
<template>
<div>
<h3>插槽的基础使用</h3>
<!-- 显示插槽内容 -->
<slot></slot>
</div>
</template>
<script setup lang="ts"></script>
具名插槽
具名插槽,就是有名字的插槽。
v-slot
有对应的简写 #
,因此 <template v-slot:header>
可以简写为 <template #header>
。其意思就是“将这部分模板片段传入子组件的 header 插槽中”。
1、父组件中定义具名插槽
src/App.vue
<template>
<BaseSlot>
<!-- 使用 # 号简写 -->
<template #header>
<nav>
导航栏部分
</nav>
</template>
<!-- 使用 v-slot -->
<template v-slot:main>
<div>
<main>
<ul>
<li v-for="article in articles" :key="article.id">{{ article.title }}</li>
</ul>
</main>
</div>
</template>
</BaseSlot>
</template>
<script setup lang="ts">
import {ref} from "vue"
import BaseSlot from "./components/slots/BaseSlot.vue"
const articles = ref([
{id:1, title:"我的世界真奇妙"},
{id:2, title:"王美丽呀"}
])
</script>
2、子组件使用具名插槽
src/components/slots/BaseSlot.vue
<template>
<div>
<slot name="header"></slot>
<slot name="main"></slot>
</div>
</template>
<script setup lang="ts"></script>
作用域插槽,子组件传递数据给父组件
通过上面的案例,可以发现数据传递的走向是 子组件使用父组件的数据,如果父组件要使用子组件的数据,该怎么操作?子组件中传递数据。
1、 子组件中使用自定义数据传递数据
src/components/slots/BaseSlot.vue
<template>
<div>
<!-- 2、定义一个属性 username,绑定数据是 name -->
<slot :username="name"></slot>
</div>
</template>
<script setup lang="ts">
// 1、子组件定义数据
const name:string = "王美丽的小世界"
</script>
2、父组件中使用
src/App.vue
<template>
<!-- 3、父组件插槽中使用 v-slot 接收数据 -->
<BaseSlot v-slot="slotProps">
<main>
<!-- 4、使用数据 -->
<h3>{{ slotProps.username }}</h3>
<ul>
<li v-for="article in articles" :key="article.id">{{ article.title }}</li>
</ul>
</main>
</BaseSlot>
</template>
<script setup lang="ts">
import {ref} from "vue"
import BaseSlot from "./components/slots/BaseSlot.vue"
const articles = ref([
{id:1, title:"我的世界真奇妙"},
{id:2, title:"王美丽呀"}
])
</script>
具名插槽作用
如果是具名插槽,又该如何使用数据?
1、父组件
src/App.vue
<template>
<BaseSlot>
<template #header="slotProps">
<header>
头部信息
<p>{{ slotProps.webinfo }}</p>
</header>
</template>
<template #main="slotProps">
<main>
<ul>
<li v-for="article in articles" :key="article.id">{{ article.title }}</li>
</ul>
</main>
<p>{{ slotProps.username }}</p>
</template>
</BaseSlot>
</template>
<script setup lang="ts">
import {ref} from "vue"
import BaseSlot from "./components/slots/BaseSlot.vue"
const articles = ref([
{id:1, title:"我的世界真奇妙"},
{id:2, title:"王美丽呀"}
])
</script>
2、子组件
src/components/slots/BaseSlot.vue
<template>
<slot name="header" :webinfo="info"></slot>
<slot name="main" :username="name"></slot>
</template>
<script setup lang="ts">
const info:string = '导航信息'
const name:string = '王美丽'
</script>
请登录后再评论