在做能源管理系统的时候,因为客户特殊要求,需要将表格固定表头与固定列
思路:将表格固定的部分分为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>
案例:
区间能耗统计
公共的方法:
$(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) });