重识手写固定表头固定列

在做能源管理系统的时候,因为客户特殊要求,需要将表格固定表头与固定列

思路:将表格固定的部分分为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{
        100%;
        height:100%;
        position:fixed;
        margin:0;
        padding:0;
    }
    #content{
        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{
        700px;
    }
    #content>table th{
        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;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='"+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)
    });
原文地址:https://www.cnblogs.com/pengfei25/p/9580356.html