公司要求在手机上实现复杂表头表格,可以第一列固定,其他滑动的table功能,我看了下,在elementui中有这个功能,但是它的多级表头需要实现上下级的对象关系,而后台给我们返回的数据都是用colspan,rowspan渲染表头的,所以这个插件无法使用。
然后退而求其实,使用比较简单的layui中的table,因为它的ui做的还可以。
layui table 的复杂多级表头是支持表头使用rowspan和colspan 的。
文档:https://www.layui.com/doc/modules/table.html
但是要实现固定列功能,就必须让表头的filed关键字绑定数据的key,有些像jq table和bootstrap table,都是初始化表头,设置关键字,然后自动配上数据渲染table。
我是要实现这样的表格(只是模板,每个表头配置的都不同),复杂表头,第一列固定:
奇葩的是,后台在设计程序的时候,表头和数据是分开的,他的意思就是表头单独渲染,然后数据部分根据顺序写table就行了:
分别为: 数据,表头,表描述
数据就是普通的键值对数据;
表头就是按tr给的对象,每一行的内容文字,和对应的calspan,rowspan
表描述就是告你表的标题,和表格的数据顺序是按colModel的数据展示的
虽然他安排的明明白白,按表头和表body分别渲染确实无问题,但是我要使用layui table实现复杂表头和列固定,表头就必须和数据key绑定,而表头给出的乱七八糟的colspan,rowspan以后的,处理起来很麻烦,要把它屡清楚很费脑细胞。
开始靠前端处理数据:
首先要搞清楚,colspan为1的一般都是需要绑定数据展示的,但数据中colspan为1的多行表头顺序并不能确定,所以无法按顺序为他们绑定key,此时,我想到了通过占位符,让每一行的总对象数都相同
先看看原始数据:
//循环表头数据
for(var i=0;i<headers.length;i++){
var array=[];
var header1=headers[i].colomnVos;
//console.log(header1)
//循环每列表头中的数据
for(var j=0;j<header1.length;j++){
var obj={}
//此时只是构造对象的雏形,还不能绑定field
obj={
title:header1[j].name,
rowspan:header1[j].rowspan,
colspan:header1[j].colspan,
style:{height:'auto'},
align:'center',
fake:false
}
array.push(obj)
//关键:如果colspan不为1的话,就在它后面加几个占位对象
if(header1[j].colspan!=1){
var thisColspan=header1[j].colspan;
for(var k=1;k<thisColspan;k++){
obj={
fake:true
}
array.push(obj)
}
}
}
tableCols.push(array);
}
//打印这个阶段的样子
var fuzhi=JSON.stringify(tableCols);
var fuzhi1=JSON.parse(fuzhi)
console.log(fuzhi1)
再看看处理后的数据:
此时发现,已经插入了占位对象了,但是每一行的对象总数还是不一样,这是因为有的表头rowspan并以一定为1
比如地市这一列直接跨了3行,那下面的即使把rowspan全部展开添加占位对象也会少一个对象,所以除了rowspan,还需要考虑colspan的问题。
现在可以确定的第一行的表头不管怎样,不需要考虑rowspan,将colspan全部展开必定代表表格的最大列数,那么我可以以最大列数开始纵向循环,如果上一级表头rowspan不是1,则在下面rowspan级表头这个位置也插入一个占位对象,描述很难,直接上代码:
//从第一个开始纵向循环,maxHeaderLength是表数据中获取的最大列数
for(var i=0;i<maxHeaderLength;i++){
for(var j=0;j<tableCols.length;j++){
var header1=tableCols[j];
if(!!header1[i]){
//此时,可以判断colspan为1的都有自己的数据,为其绑定field
if(header1[i].colspan==1){
if(i==0){
header1[i].field=pageConfVo[i];
header1[i].fixed='left'
}else{
header1[i].field=pageConfVo[i];
}
}
//关键:如果rowspan不为1,就在下面的表头中分别插入一个占位对象
if(header1[i].rowspan>1){
for(var k=0;k<header1[i].rowspan-1;k++){
tableCols[j+k+1].splice(i, 0, {fake:true});
}
}
}
}
}
var aaa=JSON.stringify(tableCols)
console.log(JSON.parse(aaa))
这时,再看下数据:
这就大功告成啦,可以保证每一行表头中,colspan为1所对应的列都是唯一的,所以就可以直接给他们赋值field的了。
赋值好后当然要把没用的占位对象删掉:
//最后
for(var i=0;i<tableCols.length;i++){
var header2=tableCols[i];
for(var j=0;j<header2.length;j++){
if(header2[j].fake){
header2.splice(j--,1);
}
}
}
console.log(tableCols)
最后的结果:
又回到了原始状态,但是不同的是该绑定数据key的列都绑定上了。
很不容易呀,下来粘下完整代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Layui</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="../lib/layui/css/layui.css" media="all">
<script src="../js/ipAddress.js" type="text/javascript" charset="utf-8"></script>
<!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
<style type="text/css">
#title{
font-size:16px;
font-weight:bold;
text-align: center;
line-height: 30px;
padding:10px
}
.layui-table-header{
}
.shuoming{
line-height: 26px;
background: #E8F4FF;
border-bottom:1px solid #ddd;
padding:10px;
font-size:13px
}
.shuoming .s1{
color:white;
background:#439FFF;
display: inline-block;
padding:0 10px;
border-radius: 10px;
margin-right:10px;
}
thead .layui-table-cell{
height:40px !important;
white-space:normal;
padding:0;
}
.span{
}
.tip{
line-height:60px;
color:#aaa;
font-size:16px;
text-align: center;
display: none;
}
</style>
</head>
<body>
<div class="shuoming">
<span class="s1">指标说明</span>
<span>指标口径请参阅市场部崔炎下发的指标说明,对指标有疑问或建议,请联系市场部崔炎或业支部陈哲。</span>
</div>
<div id="title">
</div>
<table id="demo" lay-filter="test"></table>
<div class="tip">
暂无数据
</div>
<script src="../js/jquery-3.3.1.min.js" type="text/javascript" charset="utf-8"></script>
<script src="../lib/layui/layui.js" charset="utf-8"></script>
<!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
<script>
var table
var tableCols=[];
var height=0;
var qryDate="";
var sign="";
var areaCode="";
var tableCode="";
var type="";
//表的裂数
var maxHeaderLength=0;
//表头文字长度
var maxTextLength=0;
//var url=baseUrl+'tongbao/getTongBaoDataJson.action';
var url='../static/data.json';
$(function(){
var args=getQueryStringArgs();
qryDate=args.qryDate;
sign=args.sign;
areaCode=args.areaCode;
tableCode=args.tableCode;
type=args.type;
$.ajax({
type: 'get',
url: url,
data:{
qryDate:qryDate,
sign:sign,
areaCode:areaCode,
tableCode:tableCode,
type:type
},
dataType: 'json',
async:false,
success: function(res){
console.log(res)
if(res.data.length==0){
$(".tip").show();
}
var data =res.data[0];
var headers=data.headThVos;
var pageConfVo= data.pageConfVo.colModels;
maxHeaderLength=parseInt(data.pageConfVo.colCount);
$("#title").html(data.pageConfVo.cTitle)
//循环表头数据
for(var i=0;i<headers.length;i++){
var array=[];
var header1=headers[i].colomnVos;
//console.log(header1)
//循环每列表头中的数据
for(var j=0;j<header1.length;j++){
var obj={}
if(header1[j].name.length>maxTextLength){
maxTextLength=header1[j].name.length;
}
//此时只是构造对象的雏形,还不能绑定field
obj={
title:header1[j].name,
rowspan:header1[j].rowspan,
colspan:header1[j].colspan,
style:{height:'auto'},
align:'center',
fake:false
}
array.push(obj)
//关键:如果colspan不为1的话,就在它后面加几个占位对象
if(header1[j].colspan!=1){
var thisColspan=header1[j].colspan;
for(var k=1;k<thisColspan;k++){
obj={
fake:true
}
array.push(obj)
}
}
}
tableCols.push(array);
}
//打印这个阶段的样子
var fuzhi=JSON.stringify(tableCols);
var fuzhi1=JSON.parse(fuzhi)
console.log(fuzhi1)
//从第一个开始纵向循环,maxHeaderLength是表数据中获取的最大列数
for(var i=0;i<maxHeaderLength;i++){
for(var j=0;j<tableCols.length;j++){
var header1=tableCols[j];
if(!!header1[i]){
//此时,可以判断colspan为1的都有自己的数据,为其绑定field
if(header1[i].colspan==1){
if(i==0){
header1[i].field=pageConfVo[i];
header1[i].fixed='left'
}else{
header1[i].field=pageConfVo[i];
}
}
//关键:如果rowspan不为1,就在下面的表头中分别插入一个占位对象
if(header1[i].rowspan>1){
for(var k=0;k<header1[i].rowspan-1;k++){
tableCols[j+k+1].splice(i, 0, {fake:true});
}
}
}
}
}
var aaa=JSON.stringify(tableCols)
console.log(JSON.parse(aaa))
//最后
for(var i=0;i<tableCols.length;i++){
var header2=tableCols[i];
for(var j=0;j<header2.length;j++){
if(header2[j].fake){
header2.splice(j--,1);
}
}
}
console.log(tableCols)
},
error:function(data) {
//console.log(data.msg);
},
});
})
layui.use('table', function(){
table = layui.table;
//console.log(height)
//第一个实例
table.render({
id:"itest",
where: {
qryDate:qryDate,
sign:sign,
areaCode:areaCode,
tableCode:tableCode,
type:type
},
elem: '#demo',
size: 'sm',
//,height: height
url: url ,//数据接口
parseData: function(res){ //res 即为原始返回的数据
//console.log(res)
var data=res.data[0];
var count=data.contents.length;
var data1=data.contents;
//console.log(height)
return {
"code": res.code, //解析接口状态
"msg": res.msg, //解析提示文本
"count": count, //解析数据长度
"data": data1 //解析数据列表
};
},
page: false, //开启分页
cols: tableCols,
cellMinWidth:100,
done: function(res, curr, count){
//如果是异步请求数据方式,res即为你接口返回的信息。
//如果是直接赋值的方式,res即为:{data: [], count: 99} data为当前页数据、count为数据总长度
console.log(res);
//得到当前页码
console.log(curr);
//得到数据总量
console.log(count);
console.log(maxTextLength)
if(maxTextLength>16){
$("thead .layui-table-cell").css("fontSize",'10px')
}
},
error:function(){
}
});
});
/* window.onresize = () => {
return (() => {
if(document.documentElement.clientHeight>document.documentElement.clientWidth){
that.titleHeight=50;
}else{
that.titleHeight=40;
}
window.screenHeight = document.documentElement.clientHeight
height = window.screenHeight-250;
//console.log(window.screenHeight)
//console.log(height)
//table.resize('itest');
table.reload('itest', {}, false)
})()
}*/
function getQueryStringArgs() {
//取得查询字符串并去掉开头的问号
var qs = (location.search.length > 0 ? location.search.substring(1) : ""),
//保存数据的对象
args = {},
//取得每一项
items = qs.length ? qs.split("&") : [],
item = null,
name = null,
value = null,
//在 for 循环中使用
i = 0,
len = items.length;
//逐个将每一项添加到 args 对象中
for(i = 0; i < len; i++) {
item = items[i].split("=");
name = decodeURIComponent(item[0]);
value = decodeURIComponent(item[1]);
if(name.length) {
args[name] = value;
}
}
return args;
}
</script>
</body>
</html>