历史小剧场
后来我才明白,造反的宋江,和招安的宋江,始终是同一个人。
为什么要造反?
造反,就是为了招安。 ----《明朝那些事儿》
概念
在日常的项目开发中,当我们在编写一个完整的组件时,不可避免的会引用一些外部组件或者自定义组件。而有些内容是在父组件中一样的,而在子组件中会对一些数据单独的处理。为了解决类似这样的问题,Vue设计出来了slot这个东西,也可以称为Vue的内容分发机制,它的主要作用就是向子组件的指定位置插入一断内容,这个内容可以是HTML或者其他组件。
默认插槽
这里有两个组件
Father
<!-- -->
<template>
<div class="category">
<Category title="今日美食推荐">
<ul>
<li v-for="item in foods" :key="item.id">{{ item.name }}</li>
</ul>
</Category>
<Category title="今日美景大赛">
<img :src="imageUrl" alt="">
</Category>
<Category title="今日电影直播">
<video :src="videoUrl" controls />
</Category>
</div>
</template>
<script setup lang="ts" name="Father">
import { reactive, ref } from 'vue';
import Category from './Category.vue'
const foods = reactive([
{
id: 1,
name: '鱼香肉丝'
},
{
id: 2,
name: '麻婆豆腐'
},
{
id: 3,
name: '大肉饼'
}
])
const imageUrl = ref('https://images.wallpaperscraft.com/image/single/japanese_apricot_flowers_buds_1252465_1280x720.jpg')
const videoUrl = ref('https://cdn.pixabay.com/video/2021/04/12/70796-538877060_large.mp4')
</script>
<style lang="scss" scoped>
.category {
display: flex;
// 均分开
justify-content: space-evenly;
}
img, video {
width: 100%;
}
</style>
Child:
<!-- -->
<template>
<div class="content">
<h2>{{ title }}</h2>
<slot>默认内容</slot>
</div>
</template>
<script setup lang="ts" name="Category">
defineProps(['title'])
</script>
<style lang="scss" scoped>
.content {
background-color: skyblue;
width: 200px;
height: 300px;
border-radius: 10px;
padding: 10px;
}
h2 {
text-align: center;
background-color: green;
color: white;
font-weight: 800;
}
</style>
具名插槽
具名插槽就是给我们的插槽起一个名字,即给插槽定义一个name属性
Child:
<!-- -->
<template>
<div class="content">
<slot name="s1">内容1</slot>
<slot name="s2">内容2</slot>
</div>
</template>
<script setup lang="ts" name="Category">
</script>
<style lang="scss" scoped>
.content {
background-color: skyblue;
width: 200px;
height: 300px;
border-radius: 10px;
padding: 10px;
}
</style>
Father:
<!-- -->
<template>
<div class="category">
<Category title="">
<template v-slot:s2>
<ul>
<li v-for="item in foods" :key="item.id">{{ item.name }}</li>
</ul>
</template>
<template v-slot:s1>
<h2>今日美食推荐</h2>
</template>
</Category>
<Category>
<template v-slot:s2>
<img :src="imageUrl" alt="" />
</template>
<template v-slot:s1>
<h2>今日美景大赛</h2>
</template>
</Category>
<Category>
<template #s2>
<video :src="videoUrl" controls></video>
</template>
<template #s1>
<h2>今日电影直播</h2>
</template>
</Category>
</div>
</template>
<script setup lang="ts" name="Father">
import { reactive, ref } from 'vue';
import Category from './Category.vue'
const foods = reactive([
{
id: 1,
name: '鱼香肉丝'
},
{
id: 2,
name: '麻婆豆腐'
},
{
id: 3,
name: '大肉饼'
}
])
const imageUrl = ref('https://images.wallpaperscraft.com/image/single/japanese_apricot_flowers_buds_1252465_1280x720.jpg')
const videoUrl = ref('https://cdn.pixabay.com/video/2021/04/12/70796-538877060_large.mp4')
</script>
<style lang="scss" scoped>
.category {
display: flex;
// 均分开
justify-content: space-evenly;
}
h2 {
text-align: center;
background-color: green;
color: white;
font-weight: 800;
}
img, video {
width: 100%;
}
</style>
作用域插槽
作用域插槽:数据在子组件那边,但根据数据生成的结构,却由父组件决定
父组件使用:变量 传递数据
<!-- -->
<template>
<div class="content">
<slot name="s1">内容1</slot>
<slot name="s2" :foods="foods">内容2</slot>
</div>
</template>
<script setup lang="ts" name="Category">
import { reactive } from 'vue';
const foods = reactive([
{
id: 1,
name: '鱼香肉丝'
},
{
id: 2,
name: '麻婆豆腐'
},
{
id: 3,
name: '大肉饼'
}
])
</script>
<style lang="scss" scoped>
.content {
background-color: skyblue;
width: 200px;
height: 300px;
border-radius: 10px;
padding: 10px;
}
</style>
父组件可以使用params读取到子组件传递过来的数据
<!-- -->
<template>
<div class="category">
<Category title="">
<template v-slot:s2="params">
<ul>
<li v-for="item in params.foods" :key="item.id">{{ item.name }}</li>
</ul>
</template>
<template v-slot:s1>
<h2>今日美食推荐</h2>
</template>
</Category>
<Category>
<!-- 解构出来 -->
<template v-slot:s2="{foods}">
<ol>
<li v-for="item in foods" :key="item.id">{{ item.name }}</li>
</ol>
</template>
<template v-slot:s1>
<h2>今日美景大赛</h2>
</template>
</Category>
<Category>
<!-- 解构出来 -->
<template #s2="{foods}">
<h4 v-for="item in foods" :key="item.id">{{ item.name }}</h4>
</template>
<template #s1>
<h2>今日电影直播</h2>
</template>
</Category>
</div>
</template>
<script setup lang="ts" name="Father">
import Category from './Category.vue'
</script>
<style lang="scss" scoped>
.category {
display: flex;
// 均分开
justify-content: space-evenly;
}
h2 {
text-align: center;
background-color: green;
color: white;
font-weight: 800;
}
img, video {
width: 100%;
}
</style>