【Vue】Vue3.0(二十五)Vue3.0中的具名插槽 的概念和使用场景
上篇文章 【Vue】Vue3.0(二十四)Vue3.0中 r e f s 、 refs 、 refs、parent 的概念和使用场景
🏡作者主页:点击!
🤖Vue专栏:点击!
⏰️创作时间:2024年11月20日16点30分
文章目录
- 概念
- 使用场景
- 使用示例
- 再来个实例
概念
在Vue 3.0中,具名插槽是插槽的一种特殊形式,它允许父组件向子组件的特定位置插入内容,通过给插槽命名来实现更精确的内容分发。与默认插槽不同,具名插槽可以在一个子组件中定义多个不同名称的插槽,父组件根据这些名称将相应的内容插入到对应的位置,从而使子组件的结构更加灵活和可定制。
使用场景
- 复杂组件的内容定制:当一个组件的内部结构较为复杂,不同部分需要由父组件根据具体业务场景提供不同内容时,具名插槽就非常有用。比如一个包含导航栏、主体内容区和侧边栏的页面布局组件,通过具名插槽,父组件可以分别向这三个区域插入不同的导航链接、具体的页面内容和侧边栏信息,实现页面布局和内容的灵活组合。
- 组件库的开发:在开发组件库时,具名插槽可以让使用者更方便地对组件进行个性化定制。例如,一个通用的卡片组件,可能有标题、内容、操作按钮等不同的区域,通过具名插槽,使用者可以根据自己的需求向这些区域插入不同的文本、图标或按钮等内容,而无需修改组件库的源代码,提高了组件的复用性和灵活性。
使用示例
以下是一个使用具名插槽的示例,包含一个Card
组件和使用该组件的父组件:
Card
组件
<template>
<div class="card">
<div class="card-header">
<slot name="header"></slot>
</div>
<div class="card-body">
<slot name="body"></slot>
</div>
<div class="card-footer">
<slot name="footer"></slot>
</div>
</div>
</template>
<script setup lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({});
</script>
<style scoped>
.card {
border: 1px solid #ccc;
border-radius: 5px;
overflow: hidden;
}
.card-header {
background-color: #f0f0f0;
padding: 10px;
font-weight: bold;
}
.card-body {
padding: 10px;
}
.card-footer {
background-color: #f0f0f0;
padding: 10px;
text-align: right;
}
</style>
在Card
组件中,定义了三个具名插槽:header
、body
和footer
,分别用于显示卡片的头部、主体和底部内容。
- 父组件使用
Card
组件
<template>
<div>
<h2>具名插槽示例</h2>
<Card>
<template v-slot:header>
<span>这是卡片的标题</span>
</template>
<template v-slot:body>
<p>这是卡片的主体内容,这里可以填写详细的信息。</p>
</template>
<template v-slot:footer>
<button>查看详情</button>
</template>
</Card>
</div>
</template>
<script setup lang="ts">
import Card from './Card.vue';
import { defineComponent } from 'vue';
export default defineComponent({
components: {
Card,
},
});
</script>
在父组件中,通过<template v-slot:header>
、<template v-slot:body>
和<template v-slot:footer>
分别向Card
组件的对应具名插槽中插入了自定义的内容,如标题、主体内容和操作按钮。这样,就可以根据不同的需求,灵活地定制Card
组件的显示内容,而无需修改Card
组件本身的代码,实现了组件的高度复用和灵活定制。
通过具名插槽,Vue 3.0的组件能够更好地满足各种复杂的页面布局和内容定制需求,提高了代码的可维护性和复用性,使开发者能够更高效地构建应用程序。
再来个实例
最终效果:
代码:
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<div class="content">
<Category>
<template v-slot:s2>
<ul>
<li
v-for="g in games"
:key="g.id"
>{{ g.name }}</li>
</ul>
</template>
<template v-slot:s1>
<h2>热门游戏列表</h2>
</template>
</Category>
<Category>
<template v-slot:s2>
<img
:src="imgUrl"
alt=""
>
</template>
<template v-slot:s1>
<h2>今日美食城市</h2>
</template>
</Category>
<Category>
<!--简写:#s2-->
<template #s2>
<video
video
:src="videoUrl"
controls
></video>
</template>
<template #s1>
<h2>今日影视推荐</h2>
</template>
</Category>
</div>
</div>
</template>
<script setup lang="ts" name="Father">
import Category from './Category.vue'
import { ref, reactive } from "vue";
let games = reactive([
{ id: 'asgytdfats01', name: '英雄联盟' },
{ id: 'asgytdfats02', name: '王者农药' },
{ id: 'asgytdfats03', name: '红色警戒' },
{ id: 'asgytdfats04', name: '斗罗大陆' }
])
let imgUrl = ref('https://z1.ax1x.com/2023/11/19/piNxLo4.jpg')
let videoUrl = ref('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4')
</script>
<style scoped>
.father {
background-color: rgb(165, 164, 164);
padding: 20px;
border-radius: 10px;
}
.content {
display: flex;
justify-content: space-evenly;
}
img,
video {
width: 100%;
}
h2 {
background-color: orange;
text-align: center;
font-size: 20px;
font-weight: 800;
}
</style>
Category.vue代码
<template>
<div class="category">
<slot name="s1">默认内容1</slot>
<slot name="s2">默认内容2</slot>
</div>
</template>
<script setup lang="ts" name="Category">
</script>
<style scoped>
.category {
background-color: skyblue;
border-radius: 10px;
box-shadow: 0 0 10px;
padding: 10px;
width: 200px;
height: 300px;
}
</style>