持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情
插槽
关于插槽,我之前并没有咋用过这玩意,因为我就是一搬砖的,leader都把业务给封装好的,我只需要知道需要传递哪些参数就行了,但是现在我觉得不行了,咋不可能永远一直搬砖吧?不然咋有进步呢?所以我认为我该好好看一下插槽的内容,然后试着自己也去封装封装组件,提升自己,让自己更有竞争力!
认识插槽
插槽是啥?有什么用?
根据我的学习,我认为插槽就是相当于props,只不过我们传递的不是数据,而是一堆template标签。为何说它相当于props呢?是因为props有默认值,我们也可以给子组件传递props值。而插槽也有默认值(当我们不传递标签时),但是当我们传递标签就会使用我们传递的值。第二,props可以有多个,而插槽也可以有多个,且不同的插槽也有属于自己的名字。
那插槽有啥用呢?其实也就是让我们的组件更复用、更有普适性。就像我们使用element plus
或者ant design vue
,他们的组件可以在不同的场景下都有用,而插槽就是这个道理,让我们的自己定义的组件也能适应不同的场景。
默认插槽
<!-- 子组件 -->
<template>
<div class="card">
<slot></slot>
</div>
</template>
<script lang="ts" setup>
</script>
<style scoped>
.card {
width: 500px;
border: 1px solid #eee;
box-shadow: 0 0 5px #eee;
}
</style>
<!-- 父组件 -->
<template>
<div>
<Card>
<h3>标题</h3>
</Card>
</div>
</template>
<script lang="ts" setup>
import { reactive, toRef, ref, toRefs, computed, watch } from "vue";
import Card from "./components/Card.vue";
</script>
结果呢:
我们发现,我们传给Card组件的<h3>标题</h3>
就在Card组件中渲染出来了,我们也可以传递其他的不同的标签内容,然后Card渲染不同的内容。
此外,我们还可以给Card组件一个默认值,它的作用就是当Card的父组件没有给Card传递内容时,就会使用自己默认的内容。
<!-- 子组件 -->
<template>
<div class="card">
<slot>默认</slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<Card></Card>
</div>
</template>
具名插槽
之前我们说过每个插槽都是有自己的名字的,默认插槽也有自己的名字,它的名字是default
.
<!-- 子组件 -->
<template>
<div class="card">
<slot name="default">默认</slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<Card v-slot:default></Card>
</div>
</template>
这和上面是等价的
当然我们也可以自己给插槽起名字:
<!-- 子组件 -->
<template>
<div class="card">
<slot name="header">默认</slot>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<Card v-slot:header>
<h3>标题</h3>
</Card>
</div>
</template>
而且Vue3还有简写形式:
<!-- 父组件 -->
<template>
<div>
<Card #header>
<h3>标题</h3>
</Card>
</div>
</template>
我们还可以设置多个插槽,并分别给插槽名字,这样我们需要哪个插槽时就使用哪个插槽:(但是我们要注意我们不能在插槽里使用插槽,当有多个插槽时,就不能在组件跟标签上书写,我们就得使用template
将其包裹然后传递给不同的插槽)
<!-- 子组件 -->
<template>
<div class="card">
<slot></slot>
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="main"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<Card>
<template #header>
<h3>标题</h3>
</template>
<template #main>
<p>您好,我叫xxx,欢迎和我做朋友呀!</p>
</template>
<template #footer>
<h3>个人介绍</h3>
</template>
</Card>
</div>
</template>
插槽的作用域
此外,我们需要注意的是:我们父组件传给子组件插槽的标签的作用域是 父组件,不管是css还是js。 也就是说,我们在哪定义的标签,那么这个标签的作用域就是哪。
<!-- 父组件 -->
<template>
<div>
<Card>
<template #header>
<h3 class="aa">{{title}}</h3>
</template>
<template #main>
<p>您好,我叫xxx,欢迎和我做朋友呀!</p>
</template>
<template #footer>
<h3>个人介绍</h3>
</template>
</Card>
</div>
</template>
<script lang="ts" setup>
import { reactive, toRef, ref, toRefs, computed, watch } from "vue";
import Card from "./components/Card.vue";
let title = '标题1'
</script>
<style scoped>
.aa {
color: red;
}
</style>
<!-- 子组件 -->
<template>
<div class="card">
<slot></slot>
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="main"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<script lang="ts" setup>let title = '标题2';</script>
<style scoped>
.card {
width: 500px;
border: 1px solid #eee;
box-shadow: 0 0 5px #eee;
display: flex;
flex-direction: column;
padding: 10px 15px;
}
.header {
border-bottom: 1px solid #ccc;
}
.footer {
background-color: rgb(247, 247, 247);
}
.aa {
color: blue;
}
</style>
我们发现,我们的h3标签的颜色和内容都是用的父组件的声明的内容,与子组件一点也没有关系。
插槽props
有时候我们想使用插槽内部的数据怎么办呢?我们一是可以使用老办法:emit字传父。但是插槽中有个额外的方法:可以将插槽的数据传给父组件。
<!-- 子组件 -->
<template>
<div class="card">
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="main" :len="[1,2,3,4,5]"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<Card>
<template #header>
<h3 class="aa">{{title}}</h3>
</template>
<template #main="mainProps">
<ul>
<li v-for="(item,index) in mainProps.len" :key="index">{{item}}</li>
</ul>
</template>
<template #footer>
<h3>个人介绍</h3>
</template>
</Card>
</div>
</template>
这样我们就开始拿到子组件插槽的内容了。关于插槽的知识点就这么多,也不难,平时开发的确用得少,主要是没啥需求让我使用它(这里的使用是包括定义插槽、使用插槽,而不仅仅是单纯的使用插槽,那经常使用)。现在又看了一遍插槽你内容,准备这几天看看公司大佬们是如何二次封装组件的吧!!!