在做能源管理系统的时候,因为客户特殊要求,需要将表格固定表头与固定列
思路:将表格固定的部分分为3快,
第一部分:表头
实现过程:
监听滚动条的滚动事件,判断滚动式是横向滚动的还是纵向滚动的,实现过程就是定义一个全局变量,滚动的时候去滚动的scrollTop对比,相同为横向,不等则为纵向,
实现代码1:
//固定表头
var beforscrollTop=$("#content")[0].scrollTop;
$("#content").css("position","relative");
$("#content").on('scroll',function(){
var s=$(this)[0].scrollTop;
buildEl3();
if(s!==beforscrollTop){
buildEl1();
}else{
buildEl2();
}
beforscrollTop=$(this)[0].scrollTop;
})
如果为纵向滚动找到页面中表头的部分进行克隆,设置克隆元素的宽度,
/*固定表头*/
function buildEl1(){
var me=$("#content");
var el1=me.find(".top-fixed");
//判断是否有el
if(!el1[0]){
me.append("<div class='top-fixed' style='position:absolute;top:0'><table style='table-layout:fixed'></table></div>");
var otbl=me.find(".otbl thead tr").children();
//创建,找到表格的第一行进行克隆
var $thead=me.find(".otbl thead").clone();
$thead.find("tr").children().each(function(idx,ele){
$(ele).each(function(i,e){
$(e).css("width",otbl.eq(idx).width()+1+"px");
$(e).css("height",otbl.eq(idx).height()+1+"px");
})
})
$("#content").find('.top-fixed table').append($thead);
}
//就设置top值
el1.css("top",me[0].scrollTop+"px")
}
第二部分:左边列
实现过程:
判断为纵向滚动时,找到需要固定的列,
1、克隆整个表格的内容,依次遍历去掉不要固定的列(多列)
2、找到第一列克隆,遍历克隆后的元素,在外层包上tr,因为不在一行(单列)outerHtml使用
实现代码(以克隆整个表格为例):
/*固定列*/
function buildEl2(){
var me=$("#content");
var el2=me.find(".left-fixed");
if(!el2[0]){
me.append("<div class='left-fixed' style='position:absolute;top:0'><table style='table-layout:fixed'></table></div>");
var otbl=me.find(".otbl tr>td:first-child");
//复制整个表格的tr,将td>2的全部删除掉
var newTr=$("#content").find(".otbl tr").clone();
newTr.each(function(idx,ele){
//原始的tr
var _tr=$("#content").find(".otbl tr:eq("+idx+")");
$(ele).children().each(function(i,e){
if(i<2){
//设置宽度
$(e).css("width",_tr.children().eq(i).width()+1+"px")
$(e).css("height",_tr.children().eq(i).height()+1+"px")
}else{
$(e).remove()
}
})
})
me.find('.left-fixed table').append(newTr);
}
//就设置left值
el2.css("left",me[0].scrollLeft+"px")
}
第三部分:顶部加左边
实现代码(以克隆整个表格为例):
function buildEl3(){
var me=$("#content");
var el3=me.find(".title-fixed");//不动的那块
if(!el3[0]){
me.append("<div class='title-fixed' style='position:absolute;top:0;left:0;background-color:#e4393c'><table style='table-layout:fixed'></table></div>");
var $cloze=$("#content").find(".otbl thead tr>th:lt(2)").clone();
var o=$("#content").find(".otbl thead tr>th:lt(2)");
$cloze.each(function(idx,ele){
$(ele).css("width",o.eq(idx).width()+1+"px");
$(ele).css("height",o.eq(idx).height()+1+"px");
})
me.find('.title-fixed table').append($cloze);
}
el3.css("top",me[0].scrollTop+"px");
el3.css("left",me[0].scrollLeft+"px");
el3.css("z-index",999)
}
效果:
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body{
width:100%;
height:100%;
position:fixed;
margin:0;
padding:0;
}
#content{
width:1000px;
height:150px;
margin:0 auto;
border:1px solid #ddd;
margin-top:20px;
overflow:auto;
position:relative
}
/*固定表头*/
/*通用*/
#content table th,#content table td{
text-align:center;
border:1px solid #ddd;
}
#content table{
border-collapse:collapse;
table-layout:fixed;
}
#content>table,#content .table-fixed table,.top-fixed table{
width:700px;
}
#content>table th{
width:100px;
}
#content .otbl thead tr:first-child{background-color:#e4393c}
.table-fixed tr:first-child{background-color:#e4393c}
#content .otbl tr td:nth-child(1),#content .otbl tr td:nth-child(2){background-color:#e4393c}
.left-fixed,.top-fixed{background-color:#e4393c}
</style>
</head>
<body>
<div id="content">
<table class="otbl">
<thead>
<tr>
<th>固定列</th>
<th>固定列</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<td>固定列</td>
<td>固定列</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>固定列</td>
<td>固定列</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>固定列</td>
<td>固定列</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>固定列</td>
<td>固定列</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>固定列</td>
<td>固定列</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>固定列</td>
<td>固定列</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>固定列</td>
<td>固定列</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
</div>
<script src="js/jquery-1.11.3.js"></script>
<script>
$(function(){
//固定表头
var beforscrollTop=$("#content")[0].scrollTop;
$("#content").css("position","relative");
$("#content").on('scroll',function(){
var s=$(this)[0].scrollTop;
buildEl3();
if(s!==beforscrollTop){
buildEl1();
}else{
buildEl2();
}
beforscrollTop=$(this)[0].scrollTop;
})
})
/*固定表头*/
function buildEl1(){
var me=$("#content");
var el1=me.find(".top-fixed");
//判断是否有el
if(!el1[0]){
me.append("<div class='top-fixed' style='position:absolute;top:0'><table style='table-layout:fixed'></table></div>");
var otbl=me.find(".otbl thead tr").children();
//创建,找到表格的第一行进行克隆
var $thead=me.find(".otbl thead").clone();
$thead.find("tr").children().each(function(idx,ele){
$(ele).each(function(i,e){
$(e).css("width",otbl.eq(idx).width()+1+"px");
$(e).css("height",otbl.eq(idx).height()+1+"px");
})
})
$("#content").find('.top-fixed table').append($thead);
}
//就设置top值
el1.css("top",me[0].scrollTop+"px")
}
/*固定列*/
function buildEl2(){
var me=$("#content");
var el2=me.find(".left-fixed");
if(!el2[0]){
me.append("<div class='left-fixed' style='position:absolute;top:0'><table style='table-layout:fixed'></table></div>");
var otbl=me.find(".otbl tr>td:first-child");
//复制整个表格的tr,将td>2的全部删除掉
var newTr=$("#content").find(".otbl tr").clone();
newTr.each(function(idx,ele){
//原始的tr
var _tr=$("#content").find(".otbl tr:eq("+idx+")");
$(ele).children().each(function(i,e){
if(i<2){
//设置宽度
$(e).css("width",_tr.children().eq(i).width()+1+"px")
$(e).css("height",_tr.children().eq(i).height()+1+"px")
}else{
$(e).remove()
}
})
})
me.find('.left-fixed table').append(newTr);
}
//就设置left值
el2.css("left",me[0].scrollLeft+"px")
}
function buildEl3(){
var me=$("#content");
var el3=me.find(".title-fixed");//不动的那块
if(!el3[0]){
me.append("<div class='title-fixed' style='position:absolute;top:0;left:0;background-color:#e4393c'><table style='table-layout:fixed'></table></div>");
var $cloze=$("#content").find(".otbl thead tr>th:lt(2)").clone();
var o=$("#content").find(".otbl thead tr>th:lt(2)");
$cloze.each(function(idx,ele){
$(ele).css("width",o.eq(idx).width()+1+"px");
$(ele).css("height",o.eq(idx).height()+1+"px");
})
me.find('.title-fixed table').append($cloze);
}
el3.css("top",me[0].scrollTop+"px");
el3.css("left",me[0].scrollLeft+"px");
el3.css("z-index",999)
}
</script>
</body>
</html>
View Code
案例:
区间能耗统计
公共的方法:
$(function(){
var beforscrollTop=$(".scroll-tbl")[0].scrollTop;
$('.scroll-tbl').on('scroll',function(){
var top=$(this)[0].scrollTop;
buildEl3();//不动的部分
if(top!==beforscrollTop){
buildEl1();//固定表头
}else{
buildEl2();//固定列
}
beforscrollTop=$(this)[0].scrollTop;
});
var Timer;
$(window).resize(function(){
Timer=setTimeout(function(){
if(Timer){clearTimeout(Timer)}
$('ul.th-fixed').each(function(index,ele){
setUlWidth($(ele),true);
});
},200);
});
})
function buildEl1(){
var me=$(".scroll-tbl");
var el=me.find('ul.th-fixed');
if(!el[0]){return false}
setUlWidth(el,el.next()[0].offsetWidth!=el[0].offsetWidth);
if(el.css('display')!=='block'){el.show();}
el.css('top',me[0].scrollTop+"px");
}
function setUlWidth(el,t){
if(!t){return false;}
el.css('width',el.next()[0].offsetWidth+'px');
el.find('li').each(function(i,e){
var w=el.next().find('thead>tr>th');
$(e).css('width',w[i].offsetWidth+'px');
$(e).css('height',w[i].offsetHeight+'px');
});
}
function buildEl2(){
var me=$(".scroll-tbl");
var el2=me.find(".left-fixed");
if(!el2[0]){
me.append("<div class='left-fixed' style='position:absolute;'><table class='table table-striped table-bordered g-tbl' style='table-layout:fixed;width:60px'></table></div>");
//设置top值
var h=$(".scroll-tbl").find("thead th:first").css("height");
$(".scroll-tbl").find(".left-fixed").css("top",h)
//复制整个表格的tr,遍历,将大于第一列的删除掉
//var newTr=$("#content-tbl").find("tr").clone();
var newTd=$("#tbl").find("tr>td:first-child").clone();
var oTd=$("#tbl").find("tr>td:first-child")
//设置td的宽度
var str="";
newTd.each(function(i,e){
$(e).css("width",oTd.eq(i).css('width'));
$(e).css("height",oTd.eq(i).css('height'));
str+='<tr>'+e.outerHTML+'</tr>';
})
me.find('.left-fixed table').append(str);
}
//就设置left值
me.find(".left-fixed").css("left",(me[0].scrollLeft)+"px")
}
function buildEl3(){
var me=$(".scroll-tbl");
var el3=me.find(".title-fixed");//不动的那块
if(!el3[0]){
me.append("<div class='title-fixed' style='position:absolute;top:0;left:0'><table style='table-layout:fixed'></table></div>");
var $cloze=me.find("thead tr:first").clone();
var o=me.find("thead tr:first");
$cloze.children().each(function(idx,ele){
if(idx==0){
var _boxType=o.children().eq(idx).css("box-sizing")//此处很重要
if(_boxType=="border-box"){
var pl=parseInt(o.children().eq(idx).css("padding-left"));
var pr=parseInt(o.children().eq(idx).css("padding-right"));
var bl=parseInt(o.children().eq(idx).css("border-right"));
var br=parseInt(o.children().eq(idx).css("border-right"));
$(ele).css("width",o.children().eq(idx).width()+pl+pr+bl+br+"px");
$(ele).css("height",o.children().eq(idx).height()+"px");
}else{
$(ele).css("width",o.children().eq(idx).width()+"px");
$(ele).css("height",o.children().eq(idx).height()+"px");
}
}else{
$(ele).remove();
}
})
me.find('.title-fixed table').append($cloze);
}
$(".scroll-tbl").find(".title-fixed").css("top",me[0].scrollTop+"px");
$(".scroll-tbl").find(".title-fixed").css("left",me[0].scrollLeft+"px");
$(".scroll-tbl").find(".title-fixed").css("z-index",999)
}
实现过程类似上面,但是中间出现了一系列的问题,总结如下:
1、克隆的时候只能克隆属性,克隆不了样式,样式的问题自己慢慢调试了
2、为克隆元素设置宽度的时候,特别需要注意,否则因为宽度问题会错位,上图因为是表格的原因,宽度有自己的计算方法
在添加固定的第二块的时候(滚动一直固定的),当用户在左侧选中很多项的时候不会出现问题,但是如果用户选中的只有两三个的时候,问题就层现了
问题分析:
因为克隆之后设置宽度时,此处的盒子模型为border-box,所以元素设置宽度的时候还需要加上元素的padding,border等
原先错误的写法
$cloze.children().each(function(idx,ele){
if(idx==0){
$(ele).css("width",o.children().eq(idx).width()+"px");
$(ele).css("height",o.children().eq(idx).height()+"px");
}else{
$(ele).remove();
}
})
正确的写法,还需改成float
$cloze.children().each(function(idx,ele){
if(idx==0){
var _boxType=o.children().eq(idx).css("box-sizing")//此处很重要
if(_boxType=="border-box"){
var pl=parseInt(o.children().eq(idx).css("padding-left"));
var pr=parseInt(o.children().eq(idx).css("padding-right"));
var bl=parseInt(o.children().eq(idx).css("border-right"));
var br=parseInt(o.children().eq(idx).css("border-right"));
$(ele).css("width",o.children().eq(idx).width()+pl+pr+bl+br+"px");
$(ele).css("height",o.children().eq(idx).height()+"px");
}else{
$(ele).css("width",o.children().eq(idx).width()+"px");
$(ele).css("height",o.children().eq(idx).height()+"px");
}
}else{
$(ele).remove();
}
})
0920修改:
问题一:左侧固定列的时候将页面缩小至一定的宽度时,然后横向拖动,这时候问题就出来了,如下
原因分析:是因为表格的宽度超过了页面的宽度,但是为什么会超过呢?这个问题当时也纠结了很久,发现时因为table的宽度加上滚动的设置了左侧列的left值加起来超过了页面的宽度,当页面宽度超过时,没有没有设置宽度,table-layout:fixed不会生效,按照表格的生成原理,表格就会进行压缩,所以就呈现出上图现象
解决办法;
第一种:为表格设置一个固定宽度,让属性table-layout:fixed生效
找到第一行中固定列的th,循环遍历加起来得出宽度
第二种:li元素模拟
将克隆列改成li模拟,找到所有的需要固定列的th,循环构建li,同时设置样式,
注意:
1、li需要浮动,ul要设置一个宽度,宽度得到方法如上
2、设置样式,li的内容溢出同时需要垂直居中,解决办法查找随笔“css分类”
实例代码(参考)
/**
* 左边列固定(元素模拟的方式)
*/
function buildEl2(){
var me=$("#tblForm");
var el2=me.find(".left-fixed1");
var w=0;//为坐标的固定部分设置宽度限制
var $tr='';
var str='';
if(!el2[0]){
me.append("<div class='left-fixed1' style='position:absolute;top:0'><ul></ul></div>");
//找到所有的th,遍历th直接构建li
var newTh=$("#content-tbl").find("th");
newTh.each(function(idx,ele){
var w=$(ele).width()+'px',h=$(ele).height()+'px',t=$(ele).text();
str+="<li style='width:"+w+";height:"+h+";'><span>"+t+"</span></li>";
})
var _tr=$("#content-tbl th:first");
if(_tr.next().next().next()[0].nodeName=='TD'){//为什么加了两个next,因为9月19号加了固定两列,
$tr=_tr.parent();
}else{
$tr=_tr.parent().next();
}
//遍历得出ul的宽度
$tr.find("th").each(function(idx,ele){
w+=$(ele).width();
})
me.find('.left-fixed1').css('width',w+4+'px');
me.find('.left-fixed1 ul').append(str);
$("#tblForm").find(".left-fixed1").css("left",me[0].scrollLeft+"px")
}else{
//就设置left值
$("#tblForm").find(".left-fixed1").css("left",me[0].scrollLeft+"px")
}
}
样式:
#tblForm .left-fixed1 ul{
border-top:1px solid #A3C0E8;
border-left:1px solid #A3C0E8;
}
#tblForm .left-fixed1 li{
text-align: center;
list-style: none;
word-break: normal;
font-size:14px;
padding:8px 0px 8px 0px;
background-color:#E2F0FF;
float:left;
border-right:1px solid #A3C0E8;
border-bottom:1px solid #A3C0E8;
}
#tblForm .left-fixed1 li>span{
display:inline-block;
vertical-align:middle;
}
#tblForm .left-fixed1 li::before{
content:'';
display:inline-block;
height:100%;
vertical-align: middle;
}
效果:
最后当浏览器触发了resize事件的时候,记得重新构建依次三块
var Timer;
$(window).resize(function(){
Timer=setTimeout(function(){
if(Timer){clearTimeout(Timer)}
//清空所有的固定部分重新构建
var el1=$('#tblForm').find(".h-fixed");//表头
var el2=$('#tblForm').find(".left-fixed");;//列
//两种方法构建,克隆和元素li模拟
var el3=$('#tblForm').find(".title-fixed");//不动的那块(克隆)
if(el1[0]){el1.remove()}
if(el2[0]){el2.remove()}
if(el3[0]){el3.remove()}
buildEl1()
buildEl2()
buildEl3()
},200)
});