📝 个人简介
⭐ 个人主页:我是段段🙋
🍊 博客领域:编程基础、前端💻
🍅 写作风格:干货!干货!都是干货!
🍑 精选专栏:Vue
🛸 支持段段:点赞👍、收藏⭐、留言💬
文章目录
前言
在写项目的时候有时候会经常遇到把行和列合并起来的情况,因为有些数据是重复渲染的,不合并行列会使表格看起来非常的混乱,如下:
而我们想要的数据是下面这种情况,将重复的行进行合并,使表格看起来简单明了,如下:
1、合并行
所谓的合并行就是将多行相同的数据变成一行来显示,直接上代码,页面的布局比较简单
<template><divclass="table"><el-table:data="tableData":span-method="objectSpanMethod"borderstyle="width: 100%"><el-table-columnprop="time"label="时间"></el-table-column><el-table-columnprop="grade"label="年级"></el-table-column><el-table-columnprop="name"label="姓名"></el-table-column><el-table-columnprop="subjects"label="科目"></el-table-column><el-table-columnprop="score"label="成绩"></el-table-column></el-table></div></template>
span-method
是el-table上属性,其值是一个
函数
,objectSpanMethod方法是用来处理合并行的返回值,tableData数据如下:
tableData:[{time:'2020-08-10',grade:'三年二班',name:'小明',subjects:'语文',score:80},{time:'2020-08-10',grade:'三年二班',name:'小明',subjects:'数学',score:80},{time:'2020-08-10',grade:'三年一班',name:'小雷',subjects:'语文',score:70},{time:'2020-08-10',grade:'三年一班',name:'小雷',subjects:'数学',score:80},{time:'2020-08-11',grade:'三年三班',name:'小花',subjects:'语文',score:60},{time:'2020-08-11',grade:'三年三班',name:'小花',subjects:'数学',score:60},],mergeObj:{},// 用来记录需要合并行的下标mergeArr:['time','grade','name','subjects','score']// 表格中的列名
首先需要对数据就行处理,就是比较当前行与上一行的值是否相等(如果是第一行数据,直接将值赋值为1)
在
mounted
中调用数据初始化数据的方法,如下:
mounted(){this.getSpanArr(this.tableData);}
// getSpanArr方法getSpanArr(data){this.mergeArr.forEach((key, index1)=>{let count =0;// 用来记录需要合并行的起始位置this.mergeObj[key]=[];// 记录每一列的合并信息
data.forEach((item, index)=>{// index == 0表示数据为第一行,直接 push 一个 1if(index ===0){this.mergeObj[key].push(1);}else{// 判断当前行是否与上一行其值相等 如果相等 在 count 记录的位置其值 +1 表示当前行需要合并 并push 一个 0 作为占位if(item[key]=== data[index -1][key]){this.mergeObj[key][count]+=1;this.mergeObj[key].push(0);}else{// 如果当前行和上一行其值不相等
count = index;// 记录当前位置 this.mergeObj[key].push(1);// 重新push 一个 1}}})})}
数据处理好之后就可以调用objectSpanMethod方法了,如下:
// objectSpanMethod方法// 默认接受四个值 { 当前行的值, 当前列的值, 行的下标, 列的下标 }objectSpanMethod({ row, column, rowIndex, columnIndex }){// 判断列的属性if(this.mergeArr.indexOf(column.property)!==-1){// 判断其值是不是为0 if(this.mergeObj[column.property][rowIndex]){return[this.mergeObj[column.property][rowIndex],1]}else{// 如果为0则为需要合并的行return[0,0];}}}
合并后的结果就是我们想要的形式:
合并行完整的代码如下:
<template><divclass="table"><el-table:data="tableData":span-method="objectSpanMethod"borderstyle="width: 100%"><el-table-columnprop="time"label="时间"></el-table-column><el-table-columnprop="grade"label="年级"></el-table-column><el-table-columnprop="name"label="姓名"></el-table-column><el-table-columnprop="subjects"label="科目"></el-table-column><el-table-columnprop="score"label="成绩"></el-table-column></el-table></div></template><script>exportdefault{name:'Table',data(){return{tableData:[{time:'2020-08-10',grade:'三年二班',name:'小明',subjects:'语文',score:80},{time:'2020-08-10',grade:'三年二班',name:'小明',subjects:'数学',score:80},{time:'2020-08-10',grade:'三年一班',name:'小雷',subjects:'语文',score:70},{time:'2020-08-10',grade:'三年一班',name:'小雷',subjects:'数学',score:80},{time:'2020-08-11',grade:'三年三班',name:'小花',subjects:'语文',score:60},{time:'2020-08-11',grade:'三年三班',name:'小花',subjects:'数学',score:60},],mergeObj:{},mergeArr:['time','grade','name','subjects','score'],};},methods:{getSpanArr(data){this.mergeArr.forEach((key, index1)=>{let count =0;// 用来记录需要合并行的起始位置this.mergeObj[key]=[];// 记录每一列的合并信息
data.forEach((item, index)=>{// index == 0表示数据为第一行,直接 push 一个 1if(index ===0){this.mergeObj[key].push(1);}else{// 判断当前行是否与上一行其值相等 如果相等 在 count 记录的位置其值 +1 表示当前行需要合并 并push 一个 0 作为占位if(item[key]=== data[index -1][key]){this.mergeObj[key][count]+=1;this.mergeObj[key].push(0);}else{// 如果当前行和上一行其值不相等
count = index;// 记录当前位置 this.mergeObj[key].push(1);// 重新push 一个 1}}})})},// 默认接受四个值 { 当前行的值, 当前列的值, 行的下标, 列的下标 }objectSpanMethod({ row, column, rowIndex, columnIndex }){// 判断列的属性if(this.mergeArr.indexOf(column.property)!==-1){// 判断其值是不是为0 if(this.mergeObj[column.property][rowIndex]){return[this.mergeObj[column.property][rowIndex],1]}else{// 如果为0则为需要合并的行return[0,0];}}}},mounted(){this.getSpanArr(this.tableData);}};</script><stylelang="stylus"scoped>
.table
height 100vh
width 100%
padding 40px
box-sizing border-box
/deep/ .el-table__body tr:hover > td
background-color: #fff;</style>
2、合并行列
调整下数据,如下:
tableData:[{time:'2020-08-10',grade:'三年二班',name:'小明',subjects:'语文',score:80},{time:'2020-08-10',grade:'三年二班',name:'小明',subjects:'数学',score:80},{time:'2020-08-10',grade:'总成绩',name:'总成绩',subjects:'总成绩',score:160},{time:'2020-08-10',grade:'三年一班',name:'小雷',subjects:'语文',score:70},{time:'2020-08-10',grade:'三年一班',name:'小雷',subjects:'数学',score:80},{time:'2020-08-10',grade:'总成绩',name:'总成绩',subjects:'总成绩',score:150},{time:'2020-08-11',grade:'三年三班',name:'小花',subjects:'语文',score:60},{time:'2020-08-11',grade:'三年三班',name:'小花',subjects:'数学',score:60},{time:'2020-08-11',grade:'总成绩',name:'总成绩',subjects:'总成绩',score:120}],
可以看到上面的数据多了一行总成绩,现在的数据在页面显示效果如下:
可以看到总成绩的三个列并没有合并,并不是我们想要的效果,所以需要换一种思路来处理数据
页面的布局也有所调整,如下:
<template><divclass="table"><el-table:data="tableData":span-method="objectSpanMethods"borderstyle="width: 100%"><templatev-for="cols in colConfigs"><!-- 无需合并的列 --><el-table-columnv-if="cols.type === 'label' && !cols.children":key="cols.prop":prop="cols.prop":label="cols.label"></el-table-column><!-- 需要合并的列 --><templatev-else-if="cols.type === 'label' && cols.children"><el-table-columnv-for="children in cols.children":key="children.prop":prop="children.prop":label="children.label"/></template></template></el-table></div></template>
tableData中的数据就是上面调整后的,还需要声明的变量如下:
// 表格的信息 需要合并的需要放在 children 中colConfigs:[{type:'label',children:[{prop:'time',label:'时间'},{prop:'grade',label:'年级'},{prop:'name',label:'姓名'},{prop:'subjects',label:'科目'},{prop:'score',label:'成绩'}]}],// 需要合并的行列信息mergeCols:[{index:0,name:'time'},{index:1,name:'grade'},{index:2,name:'name'},{index:3,name:'subjects'},{index:4,name:'score'},],// 用来记录每一个单元格的下标tableMergeIndex:[],
首先也需要处理数据,在
mounted
中调用数据初始化数据的方法,如下:
mounted(){if(this.mergeCols.length >0){this.newTableMergeData();}}
// newTableMergeData方法newTableMergeData(){for(let i =0; i <this.tableData.length; i++){for(let j =0; j <this.mergeCols.length; j++){// 初始化行、列坐标信息let rowIndex =1;let columnIndex =1;// 比较横坐标左方的第一个元素if(j >0&&this.tableData[i][this.mergeCols[j]['name']]===this.tableData[i][this.mergeCols[j -1]['name']]){
columnIndex =0;}// 比较纵坐标上方的第一个元素if(i >0&&this.tableData[i][this.mergeCols[j]['name']]===this.tableData[i -1][this.mergeCols[j]['name']]){
rowIndex =0;}// 比较横坐标右方元素if(columnIndex >0){
columnIndex =this.onColIndex(this.tableData[i], j, j +1,1,this.mergeCols.length);}// 比较纵坐标下方元素if(rowIndex >0){
rowIndex =this.onRowIndex(this.tableData, i, i +1,1,this.mergeCols[j]['name']);}let key =this.mergeCols[j]['index']+'_'+ i;this.tableMergeIndex[key]=[rowIndex, columnIndex];}}},/**
* 计算列坐标信息
* data 单元格所在行数据
* index 当前下标
* nextIndex 下一个元素坐标
* count 相同内容的数量
* maxLength 当前行的列总数
*/onColIndex(data, index, nextIndex, count, maxLength){// 比较当前单元格中的数据与同一行之后的单元格是否相同if(nextIndex < maxLength && data[this.mergeCols[index]['name']]=== data[this.mergeCols[nextIndex]['name']]){returnthis.onColIndex(data, index,++nextIndex,++count, maxLength);}return count;},/**
* 计算行坐标信息
* data 表格总数据
* index 当前下标
* nextIndex 下一个元素坐标
* count 相同内容的数量
* name 数据的key
*/onRowIndex(data, index, nextIndex, count, name){// 比较当前单元格中的数据与同一列之后的单元格是否相同if(nextIndex < data.length && data[index][name]=== data[nextIndex][name]){returnthis.onRowIndex(data, index,++nextIndex,++count, name);}return count;}
数据处理好之后就可以调用objectSpanMethods方法了,如下:
objectSpanMethods({ row, column, rowIndex, columnIndex }){let key = columnIndex +'_'+ rowIndex;if(this.tableMergeIndex[key]){returnthis.tableMergeIndex[key];}}
实现的效果图如下:
合并行列的完整代码如下:
<template><divclass="table"><el-table:data="tableData":span-method="objectSpanMethods"borderstyle="width: 100%"><templatev-for="cols in colConfigs"><!-- 无需合并的列 --><el-table-columnv-if="cols.type === 'label' && !cols.children":key="cols.prop":prop="cols.prop":label="cols.label"></el-table-column><!-- 需要合并的列 --><templatev-else-if="cols.type === 'label' && cols.children"><el-table-columnv-for="children in cols.children":key="children.prop":prop="children.prop":label="children.label"/></template></template></el-table></div></template><script>exportdefault{name:'Table',data(){return{tableData:[{time:'2020-08-10',grade:'三年二班',name:'小明',subjects:'语文',score:80},{time:'2020-08-10',grade:'三年二班',name:'小明',subjects:'数学',score:80},{time:'2020-08-10',grade:'总成绩',name:'总成绩',subjects:'总成绩',score:160},{time:'2020-08-10',grade:'三年一班',name:'小雷',subjects:'语文',score:70},{time:'2020-08-10',grade:'三年一班',name:'小雷',subjects:'数学',score:80},{time:'2020-08-10',grade:'总成绩',name:'总成绩',subjects:'总成绩',score:150},{time:'2020-08-11',grade:'三年三班',name:'小花',subjects:'语文',score:60},{time:'2020-08-11',grade:'三年三班',name:'小花',subjects:'数学',score:60},{time:'2020-08-11',grade:'总成绩',name:'总成绩',subjects:'总成绩',score:120}],// 表格的信息 需要合并的需要放在 children 中colConfigs:[{type:'label',children:[{prop:'time',label:'时间'},{prop:'grade',label:'年级'},{prop:'name',label:'姓名'},{prop:'subjects',label:'科目'},{prop:'score',label:'成绩'}]},// { type: 'label', prop: 'age', label: '年龄' }],// 需要合并的行列信息 index必须是table表格对应的下标 不能随意修改mergeCols:[{index:0,name:'time'},{index:1,name:'grade'},{index:2,name:'name'},{index:3,name:'subjects'},{index:4,name:'score'},// { index: 5, name: 'age' }],// 用来记录每一个单元格的下标tableMergeIndex:[],};},methods:{objectSpanMethods({ row, column, rowIndex, columnIndex }){let key = columnIndex +'_'+ rowIndex;if(this.tableMergeIndex[key]){returnthis.tableMergeIndex[key];}},newTableMergeData(){for(let i =0; i <this.tableData.length; i++){for(let j =0; j <this.mergeCols.length; j++){// 初始化行、列坐标信息let rowIndex =1;let columnIndex =1;// 比较横坐标左方的第一个元素if(j >0&&this.tableData[i][this.mergeCols[j]['name']]===this.tableData[i][this.mergeCols[j -1]['name']]){
columnIndex =0;}// 比较纵坐标上方的第一个元素if(i >0&&this.tableData[i][this.mergeCols[j]['name']]===this.tableData[i -1][this.mergeCols[j]['name']]){
rowIndex =0;}// 比较横坐标右方元素if(columnIndex >0){
columnIndex =this.onColIndex(this.tableData[i], j, j +1,1,this.mergeCols.length);}// 比较纵坐标下方元素if(rowIndex >0){
rowIndex =this.onRowIndex(this.tableData, i, i +1,1,this.mergeCols[j]['name']);}let key =this.mergeCols[j]['index']+'_'+ i;this.tableMergeIndex[key]=[rowIndex, columnIndex];}}},/**
* 计算列坐标信息
* data 单元格所在行数据
* index 当前下标
* nextIndex 下一个元素坐标
* count 相同内容的数量
* maxLength 当前行的列总数
*/onColIndex(data, index, nextIndex, count, maxLength){// 比较当前单元格中的数据与同一行之后的单元格是否相同if(nextIndex < maxLength && data[this.mergeCols[index]['name']]=== data[this.mergeCols[nextIndex]['name']]){returnthis.onColIndex(data, index,++nextIndex,++count, maxLength);}return count;},/**
* 计算行坐标信息
* data 表格总数据
* index 当前下标
* nextIndex 下一个元素坐标
* count 相同内容的数量
* name 数据的key
*/onRowIndex(data, index, nextIndex, count, name){// 比较当前单元格中的数据与同一列之后的单元格是否相同if(nextIndex < data.length && data[index][name]=== data[nextIndex][name]){returnthis.onRowIndex(data, index,++nextIndex,++count, name);}return count;}},mounted(){if(this.mergeCols.length >0){this.newTableMergeData();}}};</script><stylelang="stylus"scoped>
.table
height 100vh
width 100%
padding 40px
box-sizing border-box
/deep/ .el-table__body tr:hover > td
background-color: #fff;</style>
如果用不想合并的行需要在
colConfigs
中调整,如下:
// 增加一个年龄属性 但是不进行合并colConfigs:[{type:'label',children:[{prop:'time',label:'时间'},{prop:'grade',label:'年级'},{prop:'name',label:'姓名'},{prop:'subjects',label:'科目'},{prop:'score',label:'成绩'}]},{type:'label',prop:'age',label:'年龄'}]
效果图如下:
如果想要合并,需要在
mergeCols
中添加数据,如下:
mergeCols:[{index:0,name:'time'},{index:1,name:'grade'},{index:2,name:'name'},{index:3,name:'subjects'},{index:4,name:'score'},{index:5,name:'age'}// 添加需要合并的age列信息 注意index的值],
新添加的属性合并后效果图如下:
以上就是el-table表格合并行列的内容,有不懂的地方欢迎留言讨论~
版权归原作者 我是段段 所有, 如有侵权,请联系我们删除。