zoukankan      html  css  js  c++  java
  • 数据表格表头与首列固定的完全实现

    前几天项目经理跟我说有这么个需求:一个很大的表格,垂直滑动时表头固定,水平滑动里第一、二列固定。我一想这也太难实现了,直接回复说可能实现不了,可是没过会经理发个12306网站的一个现存的实现样子,汗!我只能说那我先调研下实现的成本吧。心里想想反正客户给钱,没有什么理由不做啊。

    1. 前期调研

    先打开12306网站上面的那个表格,打开浏览器调试工具,发现他们好像用的是插件(dhtmlxgrid),再看了下布局,发现它们把固定的表头和列放在一个DIV里面,心里想这样的需求肯定很常见,说不定网上早有相应插件了,于是上google搜“table header fixed  ”(个人比较喜欢用英文关键字搜索信息),第一条信息就是一个基于jquery的插件叫Fixed Header Table,而且还不要钱的,于是下载下来,研究它的源码,发现它的布局与12306上面的类似也是把固定的表头和列放在一个DIV,然后在此DIV里面放table,整体布局如下图所示:

    table_thumb1

    通过控制单元格的宽度和高度,使整体的单元格对齐,最后监听maindiv的滑动事件,当它滑动时通过js去滑动headerdiv与columndiv的滑动。其实里面最麻烦的应该是单元格对齐问题,因为单元格宽和高会随里面的内容变化(如果你想自适应的话)。

    知道实现原理后,然后对照下我实际的项目,我项目中的表格和12306中的表格有的类似,不是普通的数据表格,里面的单元格的合并,而且我项目中的表格还有分组(grounp),截个图:

    image_thumb1_thumb

    里面有编辑功能,还得在行和列分别加个total,表格够复杂吧。Fixed Header Table这个插件不支持我的表格(单元格的合并),dhtmlxgrid插件很强大,但要钱,项目中本来就有jquery了,不想再引用其它框架了,自己动手,丰衣足食!

    2. 具体实现

    2.1 简化需求

    以前的布局就是一个table,要做这种行列锁定的表格,布局肯定大改,为了简单点,我把我表格中的单元格宽度和高度固定,超出的文字用…表示,呵呵,我还是想怎么简单怎么来,这么做客户也接受。把单元格定死后,代码量会少很多。布局尽量用CSS去控制,JS只控制滑动和初始化区域大小(因为我页面是自适应的)。

    2.2 html+CSS

    先画个两行两列的表格,把整体布局定好,我做布局都先做整体,再做局部。先看下整体布局的html:

    <table>
        <thead>
            <tr >
               <th></th>
               <th>
                   <div id="Headerdiv" style=" overflow: hidden"></div>
               </th>  
            </tr>
        </thead>
        <tbody>
            <tr>
                <td >
                    <div id="Columndiv" style=" overflow: hidden"></div>
                </td>
                <td>
                    <div id="maindiv" style=" overflow: scroll" onscroll="fnScroll()"></div>
                </td>
            </tr>
        </tbody>
    </table>

    里面div的主要属性和事件都已经声明,接下来做thead里的两行固定列,第一个th的源代码:

    <th id="firstTd " class="tdborder">
        <table cellspacing="0" cellpadding="0">
            <tr>
                <td  class="tableFirstCol  txtcenter td_right td_bottom">Project</td>
                <td class="tableSecondCol   td_bottom">
                         <table cellspacing="0" cellpadding="0" class="Tamount">
                            <tr>
                                <td colspan="3" class="txtcenter td_bottom">Total</td>
                            </tr>
                            <tr>
                                <td class="current td_right">current</td>
                                <td class="scenario td_right">scenario</td>
                                <td class="different">different</td>
                            </tr>
                        </table>
                  
                  </td>
            </tr>
            <tr>
                <td class="tableFirstCol td_right">Total</td>
                <td class="tableSecondCol ">
                    <table cellpadding="0" cellspacing="0">
                          <tr>
                                <td class="current td_right"><input type="text" /></td>
                                <td class="scenario td_right"><input type="text" /</td>
                                <td class="different"><input type="text" /</td>
                            </tr>
                    </table>
                </td>
            </tr>
        </table>
        </th>

    然后是第二个th里面的Headerdiv的源代码:

    <div id="Headerdiv" >
           <table cellspacing="0" cellpadding="0"  width="1560" id="headertable" class="td_right" >
              <tr >
                <td class="td_left">
                  
                  <table cellspacing="0" cellpadding="0" class="Tamount">
                            <tr>
                                <td colspan="3"  class="txtcenter td_bottom">1999</td>
                            </tr>
                            <tr>
                                <td class="current td_right">current</td>
                                <td class="scenario td_right">scenario</td>
                                <td class="different">different</td>
                            </tr>
                        </table>
                </td>
               重复TD...
              </tr>
            <tr >
                <td class="td_left td_top">
                    <table cellpadding="0" cellspacing="0">
                          <tr>
                                <td class="current td_right"><input type="text" /></td>
                                <td class="scenario td_right"><input type="text" /</td>
                                <td class="different"><input type="text" /</td>
                            </tr>
                    </table>
    
                </td>
               重复TD...
            </tr>
            </table>
           </div>  

    大家可能注意到里面对套了这么多table有异议,本人是为了站单元格对齐才出此下策,在整个页面的制作过程中单元格的边框对齐是最烦人的。

    接下来展示固定列的html源码:

     <div id="Columndiv"  class="fixedcol">
            <table cellspacing="0" cellpadding="0" >
                <tr>
                    <td colspan="2" class="tdgroup">
                         group name group name group name group nam name group name group name
                        </td>
                </tr>
              <tr>
                <td class="tableFirstCol">Project Name 1 </td>
                <td class="tableSecondCol">
                    <table cellpadding="0" cellspacing="0">
                          <tr>
                                <td class="current td_right"><input type="text" /></td>
                                <td class="scenario td_right"><input type="text" /</td>
                                <td class="different"><input type="text" /</td>
                            </tr>
                    </table>
                </td>
              </tr>

    里面class为tdgrounp的为表格的分组名,这分组名如果太长就会换行,我会在JS里面控制maindiv里对应单元格的高度,也是JS代码里唯一控制单元格的代码。

    maindiv里的HTML就不粘出来了,里就就放了一个table。

    3.3 javascript

    接下来讲讲JS,JS 还是很简单的(基于jquery):

     $(document).ready(function () {
            fnAdjustTable();
            //先求页面给定的高度
            var _h = $("#tablediv").height();
            var _w = $("#tablediv").width();
    
            //然后设定相关div的高度
            var _head_h = $("#thead").height();
            $("#maindiv").height(_h - _head_h);
            $("#Columndiv").height(_h - _head_h - 18);//18是空出了相应滚动条的距离
            var _clo_w = $("#Columndiv").width();
            $("#Headerdiv").width(_w - _clo_w-18 );
            $("#maindiv").width(_w - _clo_w);
          
        });
    
        function fnAdjustTable() {
            //调整组名的单元格高度
            $('#Columndiv .tdgroup').each(function (i) {
                //不同浏览器这高度可能不一样,相关一两个像素
                if ($.browser.msie) {
                    $("#maindiv .tdgroup:eq(" + i + ")").height($(this).height());
                } else {
                    $("#maindiv .tdgroup:eq(" + i + ")").height($(this).height() + 1);
                }
               
            });
        }
    
        //滑动事件
         function fnScroll () {
            $('#Headerdiv').scrollLeft($('#maindiv').scrollLeft());
            $('#Columndiv').scrollTop($('#maindiv').scrollTop());
        }
  • 相关阅读:
    jQuery easyui datagrid pagenation 的分页数据格式
    Mysql操作符号
    jquery JSON的解析方式
    线程有几种状态
    工作日志2014-07-07
    leetcode
    Fragment中的setUserVisibleHint()方法调用
    Android开发:Eclipse中SqliteManager插件使用
    海南出差报告总结(案件录入与案件追踪系统)
    Python学习十四:filter()
  • 原文地址:https://www.cnblogs.com/Wenwang/p/2494555.html
Copyright © 2011-2022 走看看