Element实现复杂table表格结构的项目实践
作者:觉醒法师
Element-UI组件el-table用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。
将使用到以下两项,来完成今天demo演示:
多级表头:数据结构比较复杂的时候,可使用多级表头来展现数据的层次关系。
合并行或列:多行或多列共用一个数据时,可以合并行或列。
官方文档地址:https://element.eleme.cn/#/zh-CN/component/table
需要实现的表格如下图:
一、安装element-ui
使用npm进行安装:
npm i element-ui -S
二、表头实现
这里表头实现比较简单,代码如下:
<template> <div> <el-table :data="tableStudentData" :span-method="reconstructionStuCell" style="width: 100%"> <el-table-column type="index" label="序号" width="50"></el-table-column> <el-table-column prop="name" label="姓名" width="80"></el-table-column> <el-table-column label="科目信息"> <el-table-column prop="courseName" label="科目" width="80"></el-table-column> <el-table-column prop="date" label="日期" width="80"></el-table-column> <el-table-column prop="timeStr" label="考试时间" width="100"></el-table-column> </el-table-column> <el-table-column label="成绩信息"> <el-table-column prop="score" label="成绩" width="60"></el-table-column> <el-table-column prop="scoreTotal" label="总分" width="60"></el-table-column> <el-table-column prop="total" label="满分" width="60"></el-table-column> <el-table-column prop="totalAll" label="满分总分" width="100"> <template slot-scope="scope"> <span v-if="scope.row.totalAll">{{scope.row.totalAll}} (及格率:{{parseInt(scope.row.scoreTotal/scope.row.totalAll*100)}}%)</span> </template> </el-table-column> </el-table-column> </el-table> </div> </template> <script> export default { data(){ return { tableData: [], tableStudentData: [] } }, created() { }, methods: { /** * 合并单元格数据 */ reconstructionStuCell({ row, column, rowIndex, columnIndex }){ } //end } } </script> <style lang="scss"> </style>
此时表头效果已形成,如下图:
三、数据渲染
数据渲染这里较为复杂,这里为方便大家理解,进行逐步拆解叙述。如有更好方法,也欢迎大家指点。
3.1 模拟数据
如上图,在element-table目录中,新建data.js文件,用于存储模拟数据,代码如下:
export const studentData = [ {name: "李四", subject: [ {courseName: "语文", date: "20日", timeStr: "09:00~11:30", score: 90, total: 150}, {courseName: "政治", date: "20日", timeStr: "14:30~16:30", score: 70, total: 100}, {courseName: "数学", date: "21日", timeStr: "09:00~11:30", score: 100, total: 150}, {courseName: "历史", date: "21日", timeStr: "14:30~16:30", score: 72, total: 100}, {courseName: "英语", date: "22日", timeStr: "09:00~11:30", score: 95, total: 150}, ]}, {name: "王五", subject: [ {courseName: "语文", date: "20日", timeStr: "09:00~11:30", score: 85, total: 150}, {courseName: "政治", date: "20日", timeStr: "14:30~16:30", score: 60, total: 100}, {courseName: "数学", date: "21日", timeStr: "09:00~11:30", score: 90, total: 150}, {courseName: "历史", date: "21日", timeStr: "14:30~16:30", score: 68, total: 100}, {courseName: "英语", date: "22日", timeStr: "09:00~11:30", score: 75, total: 150}, ]}, {name: "小美", subject: [ {courseName: "语文", date: "20日", timeStr: "09:00~11:30", score: 120, total: 150}, {courseName: "政治", date: "20日", timeStr: "14:30~16:30", score: 85, total: 100}, {courseName: "数学", date: "21日", timeStr: "09:00~11:30", score: 120, total: 150}, {courseName: "历史", date: "21日", timeStr: "14:30~16:30", score: 80, total: 100}, {courseName: "英语", date: "22日", timeStr: "09:00~11:30", score: 130, total: 150}, ]} ];
页面中引入模拟数据,并赋值给表格的变量,代码如下:
<script> import { studentData } from './data.js' export default { data(){ return { tableStudentData: studentData } }, created() { }, methods: { /** * 合并单元格数据 */ reconstructionStuCell({ row, column, rowIndex, columnIndex }){ } //end } } </script>
此时表格中可以正常渲染出部分数据了,效果图如下:
3.2 数据处理
如上图会发现,科目和成绩相关信息,未显示出来。这里需要对数据进行处理下,将所有科目信息调整到 和姓名字段为同一行数据中。需要做以下几步:
- 将subject二级数据全部移至name同级的同一行数据中。
- 将name字段原数据移至subject的第一行数据中;item和sub进行合并。
- 无subject子项数据的,保持原数据输出。
在data.js中,添加重构数据reconstructionStuData()函数,代码如下:
/** * 重构学生数据 并返回 */ export const reconstructionStuData = data => { if(!Array.isArray(data)) return []; let tmpData = []; data.forEach((item, i) => { //有二级数据的进行处理 if(Array.isArray(item.subject)&&item.subject.length>0){ //循环成绩 item.subject.forEach((sub, j) => { let subData = {}; if(j==0){ //子项第一行数据,和姓名信息同行 subData = Object.assign({ }, item, sub); } //其他行数据无须添加 姓名字段信息(第一行数据会合并到结束位置,填充后也会被覆盖) else{ subData = Object.assign({ }, sub); } //if end tmpData.push( subData ); }); } //subject无子项数据,保留当前位置输出 else{ tmpData.push( Object.assign({ }, item) ); } }); return tmpData; }
引入reconstructionStuData()函数,代码如下:
<script> import { reconstructionStuData, studentData } from './data.js' export default { data(){ return { tableStudentData: studentData } }, created() { this.tableStudentData = reconstructionStuData(studentData); }, methods: { /** * 合并单元格数据 */ reconstructionStuCell({ row, column, rowIndex, columnIndex }){ } //end } } </script>
此时表格效果图如下:
3.3 图解
如上图,
- 列(姓名)位于列的第1位置(起始从0开始,所以序号为第0位置),往下合并subject数组长度位置即可。
- 列(总分)位于列的第6位置,往下合并subject数组长度位置即可。
- 列(满分总分)位于列的第8位置,往下合并subject数组长度位置即可。
这是我们会发现,methods中定义的reconstructionStuCell()函数还未使用,通过给table传入span-method方法可以实现合并行或列,方法的参数是一个对象,里面包含当前行row、当前列column、当前行号rowIndex、当前列号columnIndex四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表rowspan,第二个元素代表colspan。 也可以返回一个键名为rowspan和colspan的对象。
span-method相当于从数据单元格第一行开始,每行每列开始循环执行,想当于 9 * 15 执行135次,通过函数中 rowIndex, columnIndex字段进行判断当前循环是哪行哪列,并作对应处理。
这里我们添加以下逻辑,在每行数据中添加姓名、总分,满分总分对应columnIndex1、columnIndex6、columnIndex8字段,用来存储需要返回的colspan和rowspan数据,代码如下:
reconstructionStuCell({ row, column, rowIndex, columnIndex }){ let column1Data = row['columnIndex1']; let column6Data = row['columnIndex6']; let column8Data = row['columnIndex8']; //判断条件满足情况下,返回对应的rowspan和colspan数据 if( (column1Data&&column1Data.columnIndex==columnIndex) || //姓名组合并 (column6Data&&column6Data.columnIndex==columnIndex) || //总分组合并 column8Data&&column8Data.columnIndex==columnIndex //满分总分组合并 ){ return { rowspan: column1Data.rowspan, colspan: column1Data.colspan } } //if end }
比如执行span-method方法时,此时获取row数据中columnIndex1,columnIndex1中的columnIndex值为1,与span-method方法中columnIndex进行对比。
1、此时每行中列1都会被匹配到,列1行1返回{colspan: 1, rowspan: 5},则往下合并5个单元格;
2、列1行2返回{colspan: 0, rowspan: 0},则单元格不渲染,否则此行多一个单元格会错位;
3、列1行3,列1行4...... 同理。
列6(总分)、列8(满分总分)同理,通过columnIndex6和columnIndex8进行判断,进行单元格合并。
以上代码添加后,发现表格并无任何变化,这是因为重构数据函数中,还未添加对应的columnIndex1、columnIndex6、columnIndex8字段。
3.4 合并列 - 姓名
首先,我们来合并(姓名)这列数据,将每行数据中添加columnIndex1,子属性变量columnIndex表示合并对应的列位置。
subject有子项数据除第一行数据,后面所有rowspan和colspan为0,第1个单元往下合并后,会填充其他行空缺位置。
subject无子项数据rowspan和colspan为1,保留原位置渲染。如为0则当前单元格不被渲染,表格会错乱。
代码如下:
export const reconstructionStuData = data => { if(!Array.isArray(data)) return []; let tmpData = []; data.forEach((item, i) => { //有二级数据的进行处理 if(Array.isArray(item.subject)&&item.subject.length>0){ //循环成绩 item.subject.forEach((sub, j) => { let subData = {}; if(j==0){ //子项第一行数据,和姓名信息同行 subData = Object.assign({ columnIndex1: { columnIndex: 1, rowspan: item.subject.length, colspan: 1 } }, item, sub); } //其他行数据无须添加 姓名字段信息(第一行数据会合并到结束位置,填充后也会被覆盖) else{ subData = Object.assign({ columnIndex1: { columnIndex: 1, rowspan: 0, colspan: 0 } }, sub); } //if end tmpData.push( subData ); }); } //无子项数据,保留当前位置输出 else{ tmpData.push( Object.assign({ columnIndex1: { columnIndex: 1, rowspan: 1, colspan: 1 } }, item) ); } }); return tmpData; }
此时大家看到表格的(姓名)列,已合并到对应长度,效果图如下:
3.5 合并列 - 总分和满分总分
总分和满分总分合并部分,和(姓名)列同理,但多出一步则需计算出对应科目的总分 和 所有科目的满分总分。
增加第6列和第8列合并数据columnIndex6和columnIndex8,并新增scoreTotal和totalAll分别保存总分和满分总分结果。
代码如下:
export const reconstructionStuData = data => { if(!Array.isArray(data)) return []; let tmpData = []; data.forEach((item, i) => { //有二级数据的进行处理 if(Array.isArray(item.subject)&&item.subject.length>0){ //循环成绩 item.subject.forEach((sub, j) => { let subData = {}; if(j==0){ //子项第一行数据,和姓名信息同行 subData = Object.assign({ columnIndex1: { columnIndex: 1, rowspan: item.subject.length, colspan: 1 } }, item, sub); //计算总分 subData['scoreTotal'] = item.subject.reduce((total, value) => { return total + value.score; }, 0); subData['columnIndex6'] = { columnIndex: 6, rowspan: item.subject.length, colspan: 1 }; //计算满分总分 subData['totalAll'] = item.subject.reduce((total, value) => { return total + value.total; }, 0); subData['columnIndex8'] = { columnIndex: 8, rowspan: item.subject.length, colspan: 1 }; } //其他行数据无须添加 姓名字段信息(第一行数据会合并到结束位置,填充后也会被覆盖) else{ subData = Object.assign({ columnIndex1: { columnIndex: 1, rowspan: 0, colspan: 0 } }, sub); //总分和满分总分 被合并部分单元格填写为0 subData['columnIndex6'] = { columnIndex: 6, rowspan: 0, colspan: 0 }; subData['columnIndex8'] = { columnIndex: 8, rowspan: 0, colspan: 0 }; } //if end tmpData.push( subData ); }); } //无子项数据,保留当前位置输出 else{ tmpData.push( Object.assign({ columnIndex1: { columnIndex: 1, rowspan: 1, colspan: 1 } }, item) ); } }); return tmpData; }
此时,咱们需要的表格就被渲染出来了,如下图:
这里reconstructionStuData()函数处理能力还是相对不足,只能处理特定的表格合并。
到此这篇关于Element实现复杂table表格结构的项目实践的文章就介绍到这了,更多相关Element 复杂表格结构内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!