目录
前言
插槽(Slots)?
插槽可以实现父组件
自定义内容传递给子组件
展示,相当于一块画板
,画板就是我们的子组件,我们在上面定义好布局和固定内容,然后将需要变化
的部分空出来(挖坑),然后别人就可以根据需要在这个坑位上填充内容
插槽功能可以让我们实现组件多样化
、减少重复代码
,对于封装组件也是提供了巨大的帮助
一、基础
(一) 默认插槽
插槽的实现方式很简单,子组件需要在填充内容的部分写上标签slot
即可,然后父组件在引入子组件标签写入内容,填入的内容就会展示到子组件中
子组件
<div class="box">
<header>头部</header>
<main>
<!-- 插槽 -->
<slot></slot>
</main>
<footer>尾部</footer>
</div>
父组件
<div>
<Child>父组件定义的内容</Child>
</div>
在子组件中定义了头部和尾部,而中间的内容区域由父组件填充
(二) 具名插槽
当一个组件需要多个插槽
或需要父组件内容插入到位置上
时就需要到具名插槽
子组件
<div class="box">
<header>头部</header>
<main>
<!-- 插槽-1 -->
<slot name="main"></slot>
</main>
<footer>
<!-- 插槽-2 -->
<slot name="footer"></slot>
</footer>
</div>
父组件
<Child>
<template #main>
<button>hello</button>
</template>
<template #footer>
<p>哈哈哈哈哈</p>
</template>
</Child>
效果
(三) 作用域插槽
子组件可以通过动态绑定的方式,将子组件的值通过插槽传递给父组件
子组件
<div class="box">
<header>头部</header>
<main>
<!-- 插槽 -->
<slot name="main" :title="'Vue3'"></slot>
</main>
</div>
父组件
<Child>
<template #main="{ title }">
<p>我是子组件传递的值:{{ title }}</p>
</template>
</Child>
效果
(四) 动态插槽
动态插槽:可以根据名称去动态匹配插槽位置
子组件
<div class="box">
<header>
<!-- 插槽 -->
<slot name="header"></slot>
</header>
<main>
<!-- 插槽 -->
<slot name="main"></slot>
</main>
<footer>
<!-- 插槽 -->
<slot name="footer"></slot>
</footer>
</div>
父组件
<script setup lang="ts">
import Child from "./components/Child.vue";
const slotName = ref("main");
</script>
<template>
<div>
<Child>
<template #[slotName]> 鸡你太美 </template>
</Child>
</div>
</template>
二、实战案例
结合element-plus封装一个管理后台系统的数据表格,后台管理系统中,常见的就是数据表格的展示,一般模块就需要一个表格进行展示,但是表格有些代码是重复性的,如果每个模块都要写一份新的表格代码,那就发生耗费时间
、代码重复性高
、可维护性差
等问题,那此时就可以将表格封装成组件,并加上插槽扩大表格的可拓展性
Table封装组件
<script setup lang="ts">
interface Props {
tableColumn: any;
tableData: any;
}
defineProps<Props>();
</script>
<template>
<el-table :data="tableData" stripe style="width: 100%">
<el-table-column
v-for="column in tableColumn"
:key="column.prop"
:prop="column.prop"
:label="column.label"
/>
<el-table-column fixed="right" label="操作">
<template #default="scope">
<slot name="left"></slot>
<el-button link type="primary" size="small"> 添加 </el-button>
<el-button link type="danger" size="small">删除</el-button>
<slot name="right" :row="scope.row"></slot>
</template>
</el-table-column>
</el-table>
</template>
父组件
<script setup lang="ts">
import CyTable from "./components/CyTable.vue";
const tableColumn = [
{
label: "出生日期",
prop: "date",
},
{
label: "姓名",
prop: "name",
},
{
label: "住址",
prop: "address",
},
];
const tableData = [
{
date: "2016-05-03",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-02",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-04",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-01",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
];
</script>
<template>
<div class="box">
<header>头部</header>
<main>
<CyTable :tableColumn="tableColumn" :tableData="tableData">
<template #right="{ row }">
<p>获取</p>
{{ row }}
</template>
</CyTable>
</main>
<footer>尾部</footer>
</div>
</template>
<style scoped>
.box {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
header {
text-align: center;
width: 100%;
height: 100px;
}
main {
box-sizing: border-box;
padding: 50px;
margin: 20px;
width: 80%;
flex: 1;
background-color: skyblue;
}
footer {
text-align: center;
width: 100%;
height: 200px;
}
</style>
实现效果