前言
在前端开发中,表格是展示数据的常用组件。当表格数据量较大时,合理控制表格的展示方式,既能提升用户体验,又能优化页面布局。本文将基于 vue 和 el-table 组件,详细剖析一个可展开、收起的表格组件的实现过程。
实现思路
以下代码就实现了一个可展开和收起的表格功能,主要用于展示数据列表,并在数据量较多时提供展开和收起的交互方式,以节省页面空间。以下是具体的实现思路:
- 模板部分(html):
- 使用
el-table组件来展示数据,通过:data绑定tableData数组; - 通过
v-if条件判断shouldShowToggleButton来决定是否显示展开 / 收起按钮; - 按钮部分通过
@click绑定toggleExpand方法来切换展开 / 收起状态,同时通过@mouseenter和@mouseleave绑定事件来控制鼠标悬停状态; - 根据
isExpanded的值来显示不同的图标(el-icon-caret-top或el-icon-caret-bottom),并在鼠标悬停时根据hover状态显示或隐藏文字提示。
- 使用
- 数据定义(data):
tableData是一个包含多个对象的数组,用于模拟表格数据;isExpanded用于记录表格当前是展开还是收起状态,初始值为false(收起);hover用于记录鼠标是否悬停在按钮上,初始值为false。
- 脚本部分(js):
- 计算属性(computed):
computedStyle根据isExpanded和shouldShowToggleButton的值来动态计算表格的样式,包括最大高度和底部内边距;shouldShowToggleButton判断tableData的长度是否大于3,决定是否显示展开 / 收起按钮。
- 方法定义(methods):
toggleExpand方法用于切换 isExpanded 的值,从而实现表格的展开和收起。
- 计算属性(computed):
-
样式部分(css):
- 定义了
.chartTable和.tableWrapper的样式,用于布局和控制表格的滚动; - 定义了
.toggleBtn的样式,包括按钮的位置、颜色、背景等,以及鼠标悬停时的样式变化; - 定义了按钮内图标和文字提示的样式,通过
transform和opacity属性实现动画效果; - 使用
::-webkit-scrollbar隐藏滚动条,并通过::v-deep修改el-table单元格的内边距。
- 定义了
完整代码
<template>
<div class="chartTable">
<div class="tableWrapper" :style="computedStyle">
<el-table :data="tableData" border>
<el-table-column prop="date" label="参数名称"></el-table-column>
<el-table-column prop="name" label="总数量"></el-table-column>
<el-table-column prop="address" label="超规格数量"></el-table-column>
</el-table>
</div>
<div v-if="shouldShowToggleButton" class="toggleBtn" @click="toggleExpand" @mouseenter="hover = true" @mouseleave="hover = false">
<i :class="isExpanded ? 'el-icon-caret-top' : 'el-icon-caret-bottom'"></i>
<span class="text" :class="{ show: hover }"> {{ isExpanded ? "收起表格" : "展开表格" }}</span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
tableData: [
{
date: "2023-11-15",
name: "李小红",
address: "北京市朝阳区朝阳路 223 号",
},
{
date: "2024-03-20",
name: "张宇",
address: "广州市天河区珠江新城花城大道 33 号",
},
{
date: "2022-07-08",
name: "王建国",
address: "深圳市福田区深南大道 5002 号",
},
{
date: "2025-01-25",
name: "刘佳",
address: "成都市武侯区武侯祠大街 231 号",
},
{
date: "2023-09-12",
name: "赵晓峰",
address: "杭州市西湖区文三路 477 号",
},
{
date: "2024-12-05",
name: "孙丽",
address: "南京市鼓楼区中山北路 200 号",
},
{
date: "2025-02-18",
name: "周阳",
address: "武汉市武昌区中南路 14 号",
},
], // 模拟数据
isExpanded: false, // 表格展开/收起状态
hover: false, // 鼠标悬停状态
};
},
computed: {
// 表格样式
computedStyle() {
return {
maxHeight: this.isExpanded ? "none" : "200px",
paddingBottom: this.shouldShowToggleButton ? "40px" : "0px",
};
},
// 判断是否应显示展开/收起按钮
shouldShowToggleButton() {
return this.tableData.length > 3;
},
},
methods: {
// 切换表格展开/收起状态
toggleExpand() {
this.isExpanded = !this.isExpanded;
},
},
};
</script>
<style scoped>
.chartTable {
margin: 16px;
position: relative;
}
.tableWrapper {
overflow: auto;
}
.toggleBtn {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: absolute;
z-index: 99;
height: 40px;
line-height: 40px;
width: 100%;
bottom: 0px;
color: #d3dce6;
background: #f5f7fa;
overflow: hidden;
border: 1px solid #ebeef5;
border-top: none;
}
.toggleBtn i {
font-size: 18px;
transition: all 0.3s ease;
position: relative;
}
.toggleBtn:hover {
color: rgb(64, 158, 255);
box-shadow: 0 0 8px 0 rgba(232, 237, 250, 0.6), 0 2px 4px 0 rgba(232, 237, 250, 0.5);
}
.toggleBtn:hover i {
transform: translateX(-20px);
}
.text {
position: absolute;
bottom: -1px;
opacity: 0;
transform: translateX(30px);
transition: all 0.3s ease;
white-space: nowrap;
left: calc(50%);
}
.text.show {
opacity: 1;
transform: translateX(0);
}
::-webkit-scrollbar {
width: 0;
}
::v-deep .el-table .el-table__cell {
padding: 8px 0;
}
</style>
实现效果

封装公共组件
考虑到项目中可能多个地方都需要此功能,到时候还需要重复编写相同的代码,所以不如直接将其封装成一个公共组件进行使用。
封装的公共文件
<template>
<div class="tableExpandWrapper">
<div class="tableWrapper" :style="computedStyle">
<slot></slot>
</div>
<div v-if="shouldShowToggleButton" class="toggleBtn" @click="toggleExpand" @mouseenter="hover = true" @mouseleave="hover = false">
<i :class="isExpanded ? 'el-icon-caret-top' : 'el-icon-caret-bottom'"></i>
<span class="text" :class="{ show: hover }">
{{ isExpanded ? collapseText : expandText }}
</span>
</div>
</div>
</template>
<script>
export default {
name: "TableExpandWrapper",
props: {
// 表格数据长度,用于判断是否需要显示展开/收起按钮
dataLength: {
type: Number,
default: 0,
},
// 折叠高度
collapsedHeight: {
type: String,
default: "200px",
},
// 展开按钮文字
expandText: {
type: String,
default: "展开表格",
},
// 收起按钮文字
collapseText: {
type: String,
default: "收起表格",
},
// 显示按钮的阈值(数据长度超过此值才显示按钮)
threshold: {
type: Number,
default: 3,
},
},
data() {
return {
isExpanded: false, // 表格展开/收起状态
hover: false, // 鼠标悬停状态
};
},
computed: {
// 表格样式
computedStyle() {
return {
maxHeight: this.isExpanded ? "none" : this.collapsedHeight,
paddingBottom: this.shouldShowToggleButton ? "40px" : "0px",
};
},
// 判断是否应显示展开/收起按钮
shouldShowToggleButton() {
return this.dataLength > this.threshold;
},
},
methods: {
// 切换表格展开/收起状态
toggleExpand() {
this.isExpanded = !this.isExpanded;
this.$emit("toggle", this.isExpanded);
},
},
};
</script>
<style scoped>
.tableExpandWrapper {
margin: 16px;
position: relative;
}
.tableWrapper {
overflow: auto;
}
.toggleBtn {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: absolute;
z-index: 99;
height: 40px;
line-height: 40px;
width: 100%;
bottom: 0px;
color: #d3dce6;
background: #f5f7fa;
overflow: hidden;
border: 1px solid #ebeef5;
border-top: none;
}
.toggleBtn i {
font-size: 18px;
transition: all 0.3s ease;
position: relative;
}
.toggleBtn:hover {
color: rgb(64, 158, 255);
box-shadow: 0 0 8px 0 rgba(232, 237, 250, 0.6), 0 2px 4px 0 rgba(232, 237, 250, 0.5);
}
.toggleBtn:hover i {
transform: translateX(-20px);
}
.text {
position: absolute;
bottom: -1px;
opacity: 0;
transform: translateX(30px);
transition: all 0.3s ease;
white-space: nowrap;
left: calc(50%);
}
.text.show {
opacity: 1;
transform: translateX(0);
}
.tableWrapper::-webkit-scrollbar {
width: 0;
}
::v-deep .el-table .el-table__cell {
padding: 8px 0;
}
</style>
任意使用文件
<template>
<div>
<TableExpandWrapper :data-length="tableData.length">
<el-table :data="tableData" border>
<el-table-column prop="date" label="日期"></el-table-column>
<el-table-column prop="name" label="姓名"></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
</el-table>
</TableExpandWrapper>
</div>
</template>
<script>
import TableExpandWrapper from '@/components/TableExpandWrapper.vue'
export default {
components: {
TableExpandWrapper,
},
data() {
return {
tableData: [
{
date: "2023-11-15",
name: "李小红",
address: "北京市朝阳区朝阳路 223 号",
},
{
date: "2024-03-20",
name: "张宇",
address: "广州市天河区珠江新城花城大道 33 号",
},
{
date: "2022-07-08",
name: "王建国",
address: "深圳市福田区深南大道 5002 号",
},
{
date: "2025-01-25",
name: "刘佳",
address: "成都市武侯区武侯祠大街 231 号",
},
{
date: "2023-09-12",
name: "赵晓峰",
address: "杭州市西湖区文三路 477 号",
},
{
date: "2024-12-05",
name: "孙丽",
address: "南京市鼓楼区中山北路 200 号",
},
{
date: "2025-02-18",
name: "周阳",
address: "武汉市武昌区中南路 14 号",
},
],
};
},
};
</script>
封装成公共组件有以下几个重要原因:
-
代码复用 (DRY 原则)
- 避免重复:项目中多个地方需要相同功能时,不需要重复编写相同代码;
- 一处修改全局生效:如果需要调整展开/收起逻辑或样式,只需修改公共组件一处。
-
关注点分离
- 单一职责原则:组件只负责表格的展开/收起功能,不关心表格具体内容和业务逻辑;
- 降低耦合度:表格内容通过插槽注入,组件不依赖具体表格实现。
-
统一用户体验
- 一致性:保证整个项目中所有可展开表格的行为和视觉风格一致;
- 标准化:提供统一的交互方式和动画效果。
-
可维护性提升
- 逻辑集中:所有展开/收起相关代码集中管理,便于维护和调试;
- 接口清晰:通过明确的
props和事件与父组件通信,降低理解成本。
-
灵活性增强
- 可配置性:通过
props暴露关键参数(如折叠高度、阈值等),适应不同场景需求; - 扩展性:未来添加新功能(如动画效果、记住状态等)只需修改组件内部。
- 可配置性:通过

9113

被折叠的 条评论
为什么被折叠?



