Vue复杂表格(动态组合表头,跨行)
先上效果图:如果只是需要这样的表头,那么iview就可以做到(项目使用的iview),但是遇到这种既需要复杂表头,又需要跨行的情况,查了一下,好多都说让改iview源码,。。。就想着自己写一个。渣渣的我来说,哈,很有成就感。希望大家提出建议。下面是具体思路:1.首先是对表头的数据进行处理。使用了和iview Table columns属性同样的格式存值。columns...
·
先上效果图:
如果只是需要这样的表头,那么iview就可以做到(项目使用的iview),但是遇到这种既需要复杂表头,又需要跨行的情况,查了一下,好多都说让改iview源码,。。。就想着自己写一个。
渣渣的我来说,哈,很有成就感。希望大家提出建议。
下面是具体思路:
1.首先是对表头的数据进行处理。
使用了和iview Table columns属性同样的格式存值。
columns : [
{
title: '种类',
key: 'type', //这一列值所对应的key
hasrowspan:true // 在这里增加了一个属性,表示这一列是可能需要合并列的,后面会说
},
{
title: '编制人数',
key: 'amount',
},
{
title: '参数',
children: [ //children表示参数下有子标题,可以嵌套多个children
{
title: '大小',
key: 'size',
align: 'center',
},
........
],
},
.........
],
在处理columns时需要得到的数据有:
- 一个最大行数maxHeight:表头一共占用几行
- 一个二维数组 newArr :从效果图中可以看到本例的thead一共需要两个tr。newArr[0],newArr[2]分别代表第一个和第二个tr所需要的值。
- needRowSpan:哪些列需要进行跨行处理,保存需要跨行处理的key值
- colKeyList:保存所有的key,(tbody中的数据是按照表头的顺序显示,它们使用key连接)
2.处理表中的数据,数据的格式很简单,其中key值就是上面column中所对应的key,它将决定将值展示在哪一列。
dataList: [
{
type: "图书",
date: "2018-11-26",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "图书",
date: "2018-11-26",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
.......
],
在对这个数据进行处理时,要得到的数据有:
span:{} 格式如下,这是一个对象,表示哪一列的哪一行(对应td位置)rowspan的值(span中不存在时为1)
span:{
date: {0: 5, 5: 5}, //key为‘date’的列,第一个td需要跨5行,第六td需要跨5行
type: {0: 2, 2: 2, 4: 3, 7: 3}
}
- 在dataList每个对象中加入一个属性tdList,用来存放这一行所需要的key。原因:
如果某一行有一列(td)跨了两行,那么它的下一行就要少一个td
那么在这里就用少一个key来实现少一个td。
直接上完整代码:
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>多表头表格</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
</head>
<body>
<div id="app">
<table class="table">
<thead>
<tr v-for="items in newArr">
<th v-for="item in items" :rowspan="item.rowspan" :colspan="item.colspan">{{item.title}}</th>
</tr>
</thead>
<tbody v-if="needRowSpan.length>0">
<tr v-for="(items,index) in dataList">
<td v-for="item in items.tdList" :rowspan="resetRowSpan(index,item)">{{items[item]}}</td>
</tr>
</tbody>
<tbody v-else>
<tr v-for="(items,index) in dataList">
<td v-for="item in colKeyList">{{items[item]}}</td>
</tr>
</tbody>
</table>
</div>
</body>
<script>
var app = new Vue({
el: '#app',
data(){
return{
columns : [
{
title: '种类',
key: 'type',
hasrowspan:true
},
{
title: '编制人数',
key: 'amount',
},
{
title: '日期',
key: 'date',
hasrowspan:true
},
{
title: '参数',
children: [
{
title: '大小',
key: 'size',
align: 'center',
},
{
title: '参数1',
key: 'param1',
align: 'center',
},
{
title: '参数2',
key: 'param2',
align: 'center',
},
{
title: '参数3',
key: 'param3',
align: 'center',
},
],
},
{
title: '数据',
align: 'center',
children: [
{
title: '数据1',
key: 'infor1',
align: 'center',
},
{
title: '数据2',
key: 'infor2',
align: 'center',
},
{
title: '数据3',
key: 'infor3',
align: 'center',
},
{
title: '数据4',
key: 'infor4',
align: 'center',
},
],
},
], //表头原始参数
newArr:[[]], //表头
maxHeight:1, //表头总共占的行数
colKeyList:[], //所有的key
dataList: [
{
type: "图书",
date: "2018-11-26",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "图书",
date: "2018-11-26",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "电子书",
date: "2018-11-26",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "电子书",
date: "2018-11-26",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "化妆品",
date: "2018-11-26",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "化妆品",
date: "2018-11-27",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "化妆品",
date: "2018-11-27",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "水果",
date: "2018-11-27",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "水果",
date: "2018-11-27",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
{
type: "水果",
date: "2018-11-27",
amount: 0,
size: 0,
param1: 0,
param2: 0,
param3: 0,
infor1: 0,
infor2: 0,
infor3: 0,
infor4: 0,
},
], //tbody具体数据
needRowSpan:[], //tbody需要跨行的key
span:{} //所跨的行数
}
},
mounted(){
this.maxHeight=this.getMaxFloor(this.columns); //1. 计算出表头一共需要多少行
this.columnsHandle(this.columns); //2. 对表头进行处理
this.dataHandle(this.dataList,this.needRowSpan); // 3. 对数据进行处理(传入参数: 具体数据,需要跨行列的(key))
},
methods: {
resetRowSpan(row, key) {
if (this.span[key] && this.span[key][row]) {
return this.span[key][row];
}
return 1;
},
gerMaxCol(items) {
let max = 0;
function each(data) {
if (max < data.length) {
max = data.length;
}
data.forEach((item) => {
if (item.children) {
each(item.children);
}
});
}
each(items);
return max;
},
getMaxFloor(treeData) {
const that = this;
let max = 0;
function each(data, floor) {
data.forEach((e) => {
if (floor > max) {
max = floor;
}
if (e.children && e.children.length > 0) {
each(e.children, floor + 1);
}
});
}
each(treeData, 1);
return max;
},
columnsHandle(treeData) {
const that = this;
const maxFloor = this.maxHeight;
const keyList = [];
function each(data, index) {
if (that.newArr[index] === undefined) {
that.newArr[index] = [];
}
data.forEach((e) => {
const obj = {
title: e.title,
key: e.key,
rowspan: maxFloor,
colspan: 1,
};
if (e.children) {
obj.colspan = that.gerMaxCol(e.children);
obj.rowspan = maxFloor - that.getMaxFloor(e.children);
} else {
that.colKeyList.push(e.key);
if (e.hasrowspan) { // 如果存在hasrowspan属性并且值为true,则表明该key列存在跨行
that.needRowSpan.push(e.key);
}
}
that.newArr[index].push(obj);
if (e.children && e.children.length > 0) {
each(e.children, index + 1);
}
});
}
each(treeData, 0);
},
dataHandle(dataList, needRowSpan) {
needRowSpan.forEach((key) => {
const sum = {};
let i = 0; let k = 0;
const that = this;
for (let j = 0; j < dataList.length; j += 1) {
i += 1;
let tdList = [];
if (dataList[j].tdList) {
tdList = [...dataList[j].tdList];
} else {
tdList = [...that.colKeyList];
}
if (dataList[j - 1] && (dataList[j][key] === dataList[j - 1][key] || !dataList[j][key])) {
const index = tdList.indexOf(key);
if (index > -1) {
tdList.splice(index, 1);
}
}
dataList[j].tdList = tdList;
if (dataList[j + 1] && dataList[j + 1][key]) {
if (dataList[j][key] !== dataList[j + 1][key]) {
sum[k] = i;
i = 0; k = j + 1;
}
} else if (!dataList[j + 1]) {
sum[k] = i;
}
}
this.span[key] = sum;
});
console.log(this.span);
this.showTable = true;
},
}
});
</script>
<style>
#app .table {
width:100%;
border-collapse:collapse;
font-size:12px;
color: #515a6e;
border:1px solid #515a6e;
}
.table thead tr th{
height: 40px;
white-space: nowrap;
overflow: hidden;
background-color: #f8f8f9;
}
td, th
{
text-align:center;
border:1px solid #e8eaec;
}
/*tr:hover{*/
/*background:#EBF7FF;*/
/*}*/
.table thead tr th ,.table tbody tr td{
padding:0 10px;
}
.table tbody tr td{
height:48px;
}
</style>
</html>
更多推荐
已为社区贡献3条内容
所有评论(0)