关于javascript:具有固定标题的HTML表?

HTML table with fixed headers?

是否有跨浏览器的CSS / JavaScript技术来显示较长的HTML表,以使列标题在屏幕上保持固定,并且不随表主体滚动。 考虑一下Microsoft Excel中的"冻结窗格"效果。

我希望能够滚动浏览表的内容,但始终能够看到顶部的列标题。


这可以用四行代码来彻底解决。

如果您只关心现代浏览器,则可以使用CSS转换轻松实现固定标头。听起来很奇怪,但效果很好:

  • HTML和CSS保持不变。
  • 没有外部JavaScript依赖项。
  • 四行代码。
  • 适用于所有配置(表布局:固定等)。
1
2
3
4
document.getElementById("wrap").addEventListener("scroll", function(){
   var translate ="translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

除InternetExplorer8-外,对CSS转换的支持广泛可用。

这是完整的示例供参考:

1
2
3
4
document.getElementById("wrap").addEventListener("scroll",function(){
   var translate ="translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});
1
2
3
4
5
6
7
8
9
10
11
12
/* Your existing container */
#wrap {
    overflow: auto;
    height: 400px;
}

/* CSS for demo */
td {
    background-color: green;
    width: 200px;
    height: 100px;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <table>
        <thead>
            <tr>
                <th>Foo</th>
                <th>Bar</th>
            </tr>
        </thead>
        <tbody>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
            <tr><td></td><td></td></tr>
        </tbody>
    </table>


一段时间以来,我一直在寻找解决方案,但发现大多数答案都不起作用或不适合我的情况,因此我用jQuery写了一个简单的解决方案。

这是解决方案概述:

  • 克隆需要具有固定标题的表,然后将
    原始副本上的克隆副本。
  • 从顶部桌子上取下桌子主体。
  • 从底部表格中删除表格标题。
  • 调整列宽。 (我们会跟踪原始列宽)
  • 以下是可运行演示中的代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    function scrolify(tblAsJQueryObject, height) {
      var oTbl = tblAsJQueryObject;

      // for very large tables you can remove the four lines below
      // and wrap the table with  in the mark-up and assign
      // height and overflow property  
      var oTblDiv = $("");
      oTblDiv.css('height', height);
      oTblDiv.css('overflow', 'scroll');
      oTbl.wrap(oTblDiv);

      // save original width
      oTbl.attr("data-item-original-width", oTbl.width());
      oTbl.find('thead tr td').each(function() {
        $(this).attr("data-item-original-width", $(this).width());
      });
      oTbl.find('tbody tr:eq(0) td').each(function() {
        $(this).attr("data-item-original-width", $(this).width());
      });


      // clone the original table
      var newTbl = oTbl.clone();

      // remove table header from original table
      oTbl.find('thead tr').remove();
      // remove table body from new table
      newTbl.find('tbody tr').remove();

      oTbl.parent().parent().prepend(newTbl);
      newTbl.wrap("");

      // replace ORIGINAL COLUMN width             
      newTbl.width(newTbl.attr('data-item-original-width'));
      newTbl.find('thead tr td').each(function() {
        $(this).width($(this).attr("data-item-original-width"));
      });
      oTbl.width(oTbl.attr('data-item-original-width'));
      oTbl.find('tbody tr:eq(0) td').each(function() {
        $(this).width($(this).attr("data-item-original-width"));
      });
    }

    $(document).ready(function() {
      scrolify($('#tblNeedsScrolling'), 160); // 160 is height
    });
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js">


      <table border="1" width="100%" id="tblNeedsScrolling">
        <thead>
          <tr><th>Header 1</th><th>Header 2</th></tr>
        </thead>
        <tbody>
          <tr><td>row 1, cell 1</td><td>row 1, cell 2</td></tr>
          <tr><td>row 2, cell 1</td><td>row 2, cell 2</td></tr>
          <tr><td>row 3, cell 1</td><td>row 3, cell 2</td></tr>
          <tr><td>row 4, cell 1</td><td>row 4, cell 2</td></tr>        
          <tr><td>row 5, cell 1</td><td>row 5, cell 2</td></tr>
          <tr><td>row 6, cell 1</td><td>row 6, cell 2</td></tr>
          <tr><td>row 7, cell 1</td><td>row 7, cell 2</td></tr>
          <tr><td>row 8, cell 1</td><td>row 8, cell 2</td></tr>        
        </tbody>
      </table>

    此解决方案可在Chrome和IE中使用。由于它基于jQuery,因此它也应该在其他受jQuery支持的浏览器中也可以使用。


    我刚刚完成一个jQuery插件的组装,该插件将使用有效的HTML来获取有效的单个表(必须具有thead和tbody),并将输出具有固定页眉,可选固定页脚的表,该页脚可以是克隆的页眉,也可以是任何您选择的内容(分页等)。如果要利用较大的显示器,则在调整浏览器大小时,它还将调整表的大小。如果表的列不能全部适合视图,则另一个附加功能是可以侧向滚动。

    http://fixedheadertable.com/

    在github上:http://markmalek.github.com/Fixed-Header-Table/

    设置非常容易,您可以为其创建自己的自定义样式。它还在所有浏览器中使用圆角。请记住,我刚刚发布了它,因此从技术上来说它仍然是beta版,我要解决的问题很少。

    它适用于Internet Explorer 7,Internet Explorer 8,Safari,Firefox和Chrome。


    我还创建了一个可解决此问题的插件。我的项目jQuery.floatThead已经存在了4年多了,并且非常成熟。

    它不需要外部样式,也不希望您的表以任何特定方式设置样式。它支持InternetExplorer9 +和Firefox / Chrome。

    目前(2018-05)它具有:

    405 commits and 998 stars on GitHub

    这里的很多(不是全部)答案都是快速的技巧,它们可能已经解决了一个人遇到的问题,但是并不能在每个桌子上都起作用。

    其他一些插件较旧,可能与InternetExplorer兼容,但在Firefox和Chrome上将无法使用。


    TL; DR

    如果您以现代浏览器为目标,并且没有过分的样式需求:http://jsfiddle.net/dPixie/byB9d/3/ ...尽管前四个版本也很不错,但该版本在处理宽度方面要好得多。

    大家好消息!

    随着HTML5和CSS3的发展,现在已经成为可能,至少对于现代浏览器而言是这样。我想出的有点黑的实现可以在这里找到:http://jsfiddle.net/dPixie/byB9d/3/。我已经在FX 25,Chrome 31和IE 10中对其进行了测试...

    相关HTML(不过,在文档顶部插入HTML5文档类型):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    html,
    body {
      margin: 0;
      padding: 0;
      height: 100%;
    }

    section {
      position: relative;
      border: 1px solid #000;
      padding-top: 37px;
      background: #500;
    }

    section.positioned {
      position: absolute;
      top: 100px;
      left: 100px;
      width: 800px;
      box-shadow: 0 0 15px #333;
    }

    .container {
      overflow-y: auto;
      height: 200px;
    }

    table {
      border-spacing: 0;
      width: 100%;
    }

    td+td {
      border-left: 1px solid #eee;
    }

    td,
    th {
      border-bottom: 1px solid #eee;
      background: #ddd;
      color: #000;
      padding: 10px 25px;
    }

    th {
      height: 0;
      line-height: 0;
      padding-top: 0;
      padding-bottom: 0;
      color: transparent;
      border: none;
      white-space: nowrap;
    }

    th div {
      position: absolute;
      background: transparent;
      color: #fff;
      padding: 9px 25px;
      top: 0;
      margin-left: -25px;
      line-height: normal;
      border-left: 1px solid #800;
    }

    th:first-child div {
      border: none;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    <section class="positioned">
     
        <table>
          <thead>
            <tr class="header">
              <th>
                Table attribute name
                Table attribute name
              </th>
              <th>
                Value
                Value
              </th>
              <th>
                Description
                Description
              </th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>align</td>
              <td>left, center, right</td>
              <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the alignment of a table according to surrounding text</td>
            </tr>
            <tr>
              <td>bgcolor</td>
              <td>rgb(x,x,x), #xxxxxx, colorname</td>
              <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the background color for a table</td>
            </tr>
            <tr>
              <td>border</td>
              <td>1,""</td>
              <td>Specifies whether the table cells should have borders or not</td>
            </tr>
            <tr>
              <td>cellpadding</td>
              <td>pixels</td>
              <td>Not supported in HTML5. Specifies the space between the cell wall and the cell content</td>
            </tr>
            <tr>
              <td>cellspacing</td>
              <td>pixels</td>
              <td>Not supported in HTML5. Specifies the space between cells</td>
            </tr>
            <tr>
              <td>frame</td>
              <td>void, above, below, hsides, lhs, rhs, vsides, box, border</td>
              <td>Not supported in HTML5. Specifies which parts of the outside borders that should be visible</td>
            </tr>
            <tr>
              <td>rules</td>
              <td>none, groups, rows, cols, all</td>
              <td>Not supported in HTML5. Specifies which parts of the inside borders that should be visible</td>
            </tr>
            <tr>
              <td>summary</td>
              <td>text</td>
              <td>Not supported in HTML5. Specifies a summary of the content of a table</td>
            </tr>
            <tr>
              <td>width</td>
              <td>pixels, %</td>
              <td>Not supported in HTML5. Specifies the width of a table</td>
            </tr>
          </tbody>
        </table>
     
    </section>

    但是如何?

    简单地说,您有一个表头,您可以通过将其设置为0px高将其隐藏,该表头还包含用作固定头的div。表格的容器在顶部留有足够的空间以容纳绝对定位的标题,并且带有滚动条的表格如您所愿。

    上面的代码使用定位类绝对定位表(我在弹出式对话框中使用它),但是您也可以通过从容器中删除positioned类在文档流中使用它。

    但是...

    这不是完美的。 Firefox拒绝将标题行设置为0px(至少我没有找到任何方法),但顽固地将其保持在至少4px……这不是一个大问题,但是取决于您的样式,它会与边框混淆等。

    该表还使用了仿列方法,其中容器本身的背景色用作透明的标题div的背景。

    摘要

    总而言之,根据您的要求,可能会有样式问题,尤其是边框或复杂的背景。可计算性可能还存在一些问题,我尚未在各种浏览器中对其进行过检查(如果您尝试过,请在您的经验中发表评论),但是我没有找到类似的东西,因此我认为值得发布反正...


    从CSS规范之外解决此问题的所有尝试都笼罩着我们真正想要的东西:在THEAD的隐含承诺下交付。

    很长一段时间以来,这个表格冻结标题问题一直是HTML / CSS的一个开放式伤口。

    在理想的情况下,将有一个纯CSS解决此问题的方法。不幸的是,似乎没有一个合适的解决方案。

    有关此主题的相关标准的讨论包括:

    • www.style上的粘性定位建议:http://lists.w3.org/Archives/Public/www-style/2012Jun/0627.html
    • Tab Atkins关于位置根,位置包含或位置限制的建议:http://www.xanthir.com/blog/b48H0

    更新:Firefox在版本32中发布了position:sticky。每个人都赢了!


    这是固定表头的jQuery插件。它允许整个页面滚动,并在到达顶部时冻结标题。它与Twitter Bootstrap表很好地配合。

    GitHub存储库:https://github.com/oma/table-fixed-header

    它不只滚动表内容。寻找其他工具,作为其他答案之一。您可以决定最适合您的情况。


    这里发布的大多数解决方案都需要jQuery。如果您正在寻找独立于框架的解决方案,请尝试使用Grid:http://www.matts411.com/post/grid/

    它托管在Github上:https://github.com/mmurph211/Grid

    它不仅支持固定的页眉,还支持固定的左列和页脚。


    更精致的纯CSS滚动表

    到目前为止,我见过的所有纯CSS解决方案(尽管它们可能很聪明)都缺乏一定程度的改进,或者只是在某些情况下无法正常工作。因此,我决定创建自己的...

    特征:

    • 它是纯CSS,因此不需要jQuery(或完全不需要任何JavaScript代码)
      物)
    • 您可以将表格宽度设置为百分比(也称为"流体")或固定值,也可以由内容确定其宽度(也称为"自动")
    • 列宽也可以是可变的,固定的或自动的。
    • 列永远不会因水平滚动而与标题不对齐(这是我所见过的其他所有基于CSS的解决方案中都不需要固定宽度的问题)。
    • 与所有流行的桌面浏览器兼容,包括从Internet Explorer返回8版本的浏览器
    • 清洁,抛光的外观;没有马虎的1像素间隙或边框未对齐;在所有浏览器中看起来都一样

    以下是一些小提琴,它们显示了流畅和自动宽度选项:

    • 流体的宽度和高度(适合屏幕大小):jsFiddle(请注意,在此配置中,滚动条仅在需要时显示,因此您可能必须缩小框架才能看到它)

    • 自动宽度,固定高度(更易于与其他内容集成):jsFiddle

    "自动宽度,固定高度"配置可能有更多用例,因此我将在下面发布代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    /* The following 'html' and 'body' rule sets are required only
       if using a % width or height*/


    /*html {
      width: 100%;
      height: 100%;
    }*/


    body {
      box-sizing: border-box;
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0 20px 0 20px;
      text-align: center;
    }
    .scrollingtable {
      box-sizing: border-box;
      display: inline-block;
      vertical-align: middle;
      overflow: hidden;
      width: auto; /* If you want a fixed width, set it here, else set to auto */
      min-width: 0/*100%*/; /* If you want a % width, set it here, else set to 0 */
      height: 188px/*100%*/; /* Set table height here; can be fixed value or % */
      min-height: 0/*104px*/; /* If using % height, make this large enough to fit scrollbar arrows + caption + thead */
      font-family: Verdana, Tahoma, sans-serif;
      font-size: 16px;
      line-height: 20px;
      padding: 20px 0 20px 0; /* Need enough padding to make room for caption */
      text-align: left;
      color: black;
    }
    .scrollingtable * {box-sizing: border-box;}
    .scrollingtable > div {
      position: relative;
      border-top: 1px solid black;
      height: 100%;
      padding-top: 20px; /* This determines column header height */
    }
    .scrollingtable > div:before {
      top: 0;
      background: cornflowerblue; /* Header row background color */
    }
    .scrollingtable > div:before,
    .scrollingtable > div > div:after {
      content:"";
      position: absolute;
      z-index: -1;
      width: 100%;
      height: 100%;
      left: 0;
    }
    .scrollingtable > div > div {
      min-height: 0/*43px*/; /* If using % height, make this large
                                enough to fit scrollbar arrows */

      max-height: 100%;
      overflow: scroll/*auto*/; /* Set to auto if using fixed
                                   or % width; else scroll */

      overflow-x: hidden;
      border: 1px solid black; /* Border around table body */
    }
    .scrollingtable > div > div:after {background: white;} /* Match page background color */
    .scrollingtable > div > div > table {
      width: 100%;
      border-spacing: 0;
      margin-top: -20px; /* Inverse of column header height */
      /*margin-right: 17px;*/ /* Uncomment if using % width */
    }
    .scrollingtable > div > div > table > caption {
      position: absolute;
      top: -20px; /*inverse of caption height*/
      margin-top: -1px; /*inverse of border-width*/
      width: 100%;
      font-weight: bold;
      text-align: center;
    }
    .scrollingtable > div > div > table > * > tr > * {padding: 0;}
    .scrollingtable > div > div > table > thead {
      vertical-align: bottom;
      white-space: nowrap;
      text-align: center;
    }
    .scrollingtable > div > div > table > thead > tr > * > div {
      display: inline-block;
      padding: 0 6px 0 6px; /*header cell padding*/
    }
    .scrollingtable > div > div > table > thead > tr > :first-child:before {
      content:"";
      position: absolute;
      top: 0;
      left: 0;
      height: 20px; /*match column header height*/
      border-left: 1px solid black; /*leftmost header border*/
    }
    .scrollingtable > div > div > table > thead > tr > * > div[label]:before,
    .scrollingtable > div > div > table > thead > tr > * > div > div:first-child,
    .scrollingtable > div > div > table > thead > tr > * + :before {
      position: absolute;
      top: 0;
      white-space: pre-wrap;
      color: white; /*header row font color*/
    }
    .scrollingtable > div > div > table > thead > tr > * > div[label]:before,
    .scrollingtable > div > div > table > thead > tr > * > div[label]:after {content: attr(label);}
    .scrollingtable > div > div > table > thead > tr > * + :before {
      content:"";
      display: block;
      min-height: 20px; /* Match column header height */
      padding-top: 1px;
      border-left: 1px solid black; /* Borders between header cells */
    }
    .scrollingtable .scrollbarhead {float: right;}
    .scrollingtable .scrollbarhead:before {
      position: absolute;
      width: 100px;
      top: -1px; /* Inverse border-width */
      background: white; /* Match page background color */
    }
    .scrollingtable > div > div > table > tbody > tr:after {
      content:"";
      display: table-cell;
      position: relative;
      padding: 0;
      border-top: 1px solid black;
      top: -1px; /* Inverse of border width */
    }
    .scrollingtable > div > div > table > tbody {vertical-align: top;}
    .scrollingtable > div > div > table > tbody > tr {background: white;}
    .scrollingtable > div > div > table > tbody > tr > * {
      border-bottom: 1px solid black;
      padding: 0 6px 0 6px;
      height: 20px; /* Match column header height */
    }
    .scrollingtable > div > div > table > tbody:last-of-type > tr:last-child > * {border-bottom: none;}
    .scrollingtable > div > div > table > tbody > tr:nth-child(even) {background: gainsboro;} /* Alternate row color */
    .scrollingtable > div > div > table > tbody > tr > * + * {border-left: 1px solid black;} /* Borders between body cells */
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
          <table>
            <caption>Top Caption</caption>
            <thead>
              <tr>
                <th></th>
                <th></th>
                <th></th>
                <th>
                  <!-- More versatile way of doing column label; requires two identical copies of label -->
                  Column 4Column 4
                </th>
                <th class="scrollbarhead"/> <!-- ALWAYS ADD THIS EXTRA CELL AT END OF HEADER ROW -->
              </tr>
            </thead>
            <tbody>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
              <tr><td>Lorem ipsum</td><td>Dolor</td><td>Sit</td><td>Amet consectetur</td></tr>
            </tbody>
          </table>
       
        Faux bottom caption
     


    <!--[if lte IE 9]><style>.scrollingtable > div > div > table {margin-right: 17px;}</style><![endif]-->

    我用来冻结标题行的方法与d-Pixie相似,因此请参阅其帖子以获取解释。这项技术存在很多错误和局限性,只能通过堆额外的CSS和一个或多个div容器来解决。


    CSS属性position: sticky在大多数现代浏览器中都有很好的支持(Edge出现问题,请参见下文)。

    这使我们可以很轻松地解决固定标头的问题:

    1
    thead th { position: sticky; top: 0; }

    Safari需要供应商前缀:-webkit-sticky

    对于Firefox,我必须将min-height: 0添加到父元素之一。我完全忘记了为什么需要这样做。

    最不幸的是,Microsoft Edge实施似乎只是半成品。至少,我在测试中有一些闪烁且未对齐的表格单元。该桌子仍然可用,但存在重大美学问题。


    一个简单的jQuery插件

    这是Mahes解决方案的一种变体。您可以像$('table#foo').scrollableTable();这样称呼它

    这个想法是:

    • theadtbody拆分为单独的table元素
    • 使它们的单元格宽度再次匹配
    • 将第二个table包裹在div.scrollable
    • 使用CSS使div.scrollable实际滚动

    CSS可能是:

    1
    div.scrollable { height: 300px; overflow-y: scroll;}

    注意事项

    • 显然,拆分这些表会使标记的语义更少。我不确定这对可访问性有什么影响。
    • 此插件不处理页脚,多个页眉等。
    • 我仅在Chrome版本20中对其进行了测试。

    就是说,它适用于我的目的,您可以随意使用和修改它。

    这是插件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    jQuery.fn.scrollableTable = function () {
      var $newTable, $oldTable, $scrollableDiv, originalWidths;
      $oldTable = $(this);

      // Once the tables are split, their cell widths may change.
      // Grab these so we can make the two tables match again.
      originalWidths = $oldTable.find('tr:first td').map(function() {
        return $(this).width();
      });

      $newTable = $oldTable.clone();
      $oldTable.find('tbody').remove();
      $newTable.find('thead').remove();

      $.each([$oldTable, $newTable], function(index, $table) {
        $table.find('tr:first td').each(function(i) {
          $(this).width(originalWidths[i]);
        });
      });

      $scrollableDiv = $('').addClass('scrollable');
      $newTable.insertAfter($oldTable).wrap($scrollableDiv);
    };


    :)

    不太干净,但是纯HTML / CSS解决方案。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    table {
        overflow-x:scroll;
    }

    tbody {
        max-height: /*your desired max height*/
        overflow-y:scroll;
        display:block;
    }

    已针对IE8 +更新
    JSFiddle示例


    支持固定页脚

    我扩展了Nathan的功能,以支持固定的页脚和最大高度。
    另外,该函数将设置CSS本身,而您只需要支持宽度即可。

    用法:

    固定高度:

    1
    $('table').scrollableTable({ height: 100 });

    最大高度(如果浏览器支持CSS" max-height"选项):

    1
    $('table').scrollableTable({ maxHeight: 100 });

    脚本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    jQuery.fn.scrollableTable = function(options) {

        var $originalTable, $headTable, $bodyTable, $footTable, $scrollableDiv, originalWidths;

        // Prepare the separate parts of the table
        $originalTable = $(this);
        $headTable = $originalTable.clone();

        $headTable.find('tbody').remove();
        $headTable.find('tfoot').remove();

        $bodyTable = $originalTable.clone();
        $bodyTable.find('thead').remove();
        $bodyTable.find('tfoot').remove();

        $footTable = $originalTable.clone();
        $footTable.find('thead').remove();
        $footTable.find('tbody').remove();

        // Grab the original column widths and set them in the separate tables
        originalWidths = $originalTable.find('tr:first td').map(function() {
            return $(this).width();
        });

        $.each([$headTable, $bodyTable, $footTable], function(index, $table) {
            $table.find('tr:first td').each(function(i) {
                $(this).width(originalWidths[i]);
            });
        });

        // The div that makes the body table scroll
        $scrollableDiv = $('').css({
            'overflow-y': 'scroll'
        });

        if(options.height) {
            $scrollableDiv.css({'height': options.height});
        }
        else if(options.maxHeight) {
            $scrollableDiv.css({'max-height': options.maxHeight});
        }

        // Add the new separate tables and remove the original one
        $headTable.insertAfter($originalTable);
        $bodyTable.insertAfter($headTable);
        $footTable.insertAfter($bodyTable);
        $bodyTable.wrap($scrollableDiv);
        $originalTable.remove();
    };

    不知何故,我最终在Position:Sticky的情况下工作得很好:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    table{
      width: 100%;
      border: collapse;
    }

    th{
        position: sticky;
        top: 0px;
        border: 1px solid black;
        background: #ff5722;
        color: #f5f5f5;
        font-weight: 600;
    }
    td{
        background: #d3d3d3;
        border: 1px solid black;
        color: #f5f5f5;
        font-weight: 600;
    }

    div{
      height: 150px
      overflow: auto;
      width: 100%
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
        <table>
            <thead>
                <tr>
                    <th>header 1</th>
                    <th>header 2</th>
                    <th>header 3</th>
                    <th>header 4</th>
                    <th>header 5</th>
                    <th>header 6</th>
                    <th>header 7</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
                <tr>
                    <td>data 1</td>
                    <td>data 2</td>
                    <td>data 3</td>
                    <td>data 4</td>
                    <td>data 5</td>
                    <td>data 6</td>
                    <td>data 7</td>
                </tr>
            </tbody>
        </table>


    两个div,一个用于标头,一个用于数据。使数据div可滚动,并使用JavaScript将标头中的列宽设置为与数据中的宽度相同。我认为数据列的宽度需要固定而不是动态。


    对于那些尝试了Maximilian Hils给出的不错的解决方案但没有成功使其与Internet Explorer一起使用的人来说,我遇到了同样的问题(InternetExplorer11),并找出了问题所在。

    在InternetExplorer11中,样式转换(至少对于转换而言)不适用于。我通过在循环中将样式应用于所有来解决了这个问题。那行得通。我的JavaScript代码如下所示:

    1
    2
    3
    4
    5
    6
    7
    document.getElementById('pnlGridWrap').addEventListener("scroll", function () {
      var translate ="translate(0," + this.scrollTop +"px)";
      var myElements = this.querySelectorAll("th");
      for (var i = 0; i < myElements.length; i++) {
        myElements[i].style.transform=translate;
      }
    });

    在我的情况下,该表是ASP.NET中的GridView。首先,我认为这是因为它没有,但是即使我强迫它具有,它也不起作用。然后我发现了我上面写的。

    这是一个非常简单的解决方案。在Chrome上它是完美的,在Firefox上有点生涩,而在InternetExplorer上则更加生涩。但总而言之,这是一个很好的解决方案。


    我意识到这个问题允许使用JavaScript,但这是我处理过的纯CSS解决方案,它还允许表格水平扩展。它已通过InternetExplorer10以及最新的Chrome和Firefox浏览器进行了测试。底部的jsFiddle链接。

    HTML:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    Putting some text here to differentiate between the header
    aligning with the top of the screen and the header aligning
    with the top of one of its ancestor containers.



        <table>
            <colgroup>
                <col class="col1"></col>
                <col class="col2"></col>
            </colgroup>
            <thead>
                <th class="header-col1">Header 1</th>
                <th class="header-col2">Header 2</th>
            </thead>
            <tbody>
                <tr><td>Cell 1.1</td><td>Cell 1.2</td></tr>
                <tr><td>Cell 2.1</td><td>Cell 2.2</td></tr>
                <tr><td>Cell 3.1</td><td>Cell 3.2</td></tr>
                <tr><td>Cell 4.1</td><td>Cell 4.2</td></tr>
                <tr><td>Cell 5.1</td><td>Cell 5.2</td></tr>
                <tr><td>Cell 6.1</td><td>Cell 6.2</td></tr>
                <tr><td>Cell 7.1</td><td>Cell 7.2</td></tr>

            </tbody>
        </table>

    和CSS:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    table{
        border-collapse: collapse;
        table-layout: fixed;
        width: 100%;
    }
    /* Not required, just helps with alignment for this example */
    td, th{
        padding: 0;
        margin: 0;
    }

    tbody{
        background-color: #ddf;
    }

    thead {
        /* Keeps the header in place. Don't forget top: 0 */
        position: absolute;
        top: 0;
        background-color: #ddd;

        /* The 17px is to adjust for the scrollbar width.
         * This is a new css value that makes this pure
         * css example possible */

        width: calc(100% - 17px);
        height: 20px;
    }

    /* Positioning container. Required to position the
     * header since the header uses position:absolute
     * (otherwise it would position at the top of the screen) */

    #positioning-container{
        position: relative;
    }

    /* A container to set the scroll-bar and
     * includes padding to move the table contents
     * down below the header (padding = header height) */

    #scroll-container{
        overflow-y: auto;
        padding-top: 20px;
        height: 100px;
    }
    .header-col1{
        background-color: red;
    }

    /* Fixed-width header columns need a div to set their width */
    .header-col1 div{
        width: 100px;
    }

    /* Expandable columns need a width set on the th tag */
    .header-col2{
        width: 100%;
    }
    .col1 {
        width: 100px;
    }
    .col2{
        width: 100%;
    }

    http://jsfiddle.net/HNHRv/3/


    这是对马克西米利安·希尔斯(Maximilian Hils)发布的答案的改进的答案。

    这可以在InternetExplorer11中正常运行,而不会闪烁:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    var headerCells = tableWrap.querySelectorAll("thead td");
    for (var i = 0; i < headerCells.length; i++) {
        var headerCell = headerCells[i];
        headerCell.style.backgroundColor ="silver";
    }
    var lastSTop = tableWrap.scrollTop;
    tableWrap.addEventListener("scroll", function () {
        var stop = this.scrollTop;
        if (stop < lastSTop) {
            // Resetting the transform for the scrolling up to hide the headers
            for (var i = 0; i < headerCells.length; i++) {
                headerCells[i].style.transitionDelay ="0s";
                headerCells[i].style.transform ="";
            }
        }
        lastSTop = stop;
        var translate ="translate(0," + stop +"px)";
        for (var i = 0; i < headerCells.length; i++) {
            headerCells[i].style.transitionDelay ="0.25s";
            headerCells[i].style.transform = translate;
        }
    });

    我希望能早点找到@Mark的解决方案,但是在看到这个问题之前,我去写了自己的解决方案...

    我的是一个非常轻量级的jQuery插件,它支持固定的页眉,页脚,列跨度(colspan),调整大小,水平滚动以及滚动开始之前要显示的可选行数。

    jQuery.scrollTableBody(GitHub)

    只要您有一个带有正确的

    和(可选)

    的表,您要做的就是:

    1
    $('table').scrollTableBody();


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    <html>
    <head>
        <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js">
       
            function stickyTableHead (tableID) {
                var $tmain = $(tableID);
                var $tScroll = $tmain.children("thead")
                    .clone()
                    .wrapAll('<table id="tScroll" />')
                    .parent()
                    .addClass($(tableID).attr("class"))
                    .css("position","fixed")
                    .css("top","0")
                    .css("display","none")
                    .prependTo("#tMain");

                var pos = $tmain.offset().top + $tmain.find(">thead").height();


                $(document).scroll(function () {
                    var dataScroll = $tScroll.data("scroll");
                    dataScroll = dataScroll || false;
                    if ($(this).scrollTop() >= pos) {
                        if (!dataScroll) {
                            $tScroll
                                .data("scroll", true)
                                .show()
                                .find("th").each(function () {
                                    $(this).width($tmain.find(">thead>tr>th").eq($(this).index()).width());
                                });
                        }
                    } else {
                        if (dataScroll) {
                            $tScroll
                                .data("scroll", false)
                                .hide()
                            ;
                        }
                    }
                });
            }

            $(document).ready(function () {
                stickyTableHead('#tMain');
            });
       
    </head>

    <body>
        gfgfdgsfgfdgfds<br/>
        gfgfdgsfgfdgfds<br/>
        gfgfdgsfgfdgfds<br/>
        gfgfdgsfgfdgfds<br/>
        gfgfdgsfgfdgfds<br/>
        gfgfdgsfgfdgfds<br/>

        <table id="tMain">
            <thead>
            <tr>
                <th>1</th> <th>2</th><th>3</th> <th>4</th><th>5</th> <th>6</th><th>7</th> <th>8</th>

            </tr>
            </thead>
            <tbody>
                <tr><td>11111111111111111111111111111111111111111111111111111111</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
                <tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5555555</td><td>66666666666</td><td>77777777777</td><td>8888888888888888</td></tr>
            </tbody>
        </table>
    </body>
    </html>

    我开发了一个简单的轻量级jQuery插件,用于将格式正确的HTML表转换为具有固定表头和列的可滚动表。

    该插件可以很好地将固定部分与可滚动部分的像素对像素匹配。此外,您还可以冻结水平滚动时始终在视图中显示的列数。

    演示和文档:http://meetselva.github.io/fixed-table-rows-cols/

    GitHub存储库:https://github.com/meetselva/fixed-table-rows-cols

    以下是带有固定标题的简单表的用法,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $(<table selector>).fxdHdrCol({
        width:    "100%",
        height:    200,
        colModal: [{width: 30, align: 'center'},
                   {width: 70, align: 'center'},
                   {width: 200, align: 'left'},
                   {width: 100, align: 'center'},
                   {width: 70, align: 'center'},
                   {width: 250, align: 'center'}
                  ]
    });


    很多人似乎正在寻找这个答案。我发现它埋在这里的另一个问题的答案中:在两个不同框架中的表之间同步列宽,等等

    在我尝试过的数十种方法中,这是我发现的唯一一种可靠地工作的方法,该方法可以使您拥有底部宽度与标题表相同的滚动底表。

    这是我的操作方法,首先,我对上面的jsfiddle进行了改进,以创建此函数,该函数可同时在tdth上使用(以防其他人使用th设置其标题行的样式)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var setHeaderTableWidth= function (headertableid,basetableid) {
                $("#"+headertableid).width($("#"+basetableid).width());
                $("#"+headertableid+" tr th").each(function (i) {
                    $(this).width($($("#"+basetableid+" tr:first td")[i]).width());
                });
                $("#" + headertableid +" tr td").each(function (i) {
                    $(this).width($($("#" + basetableid +" tr:first td")[i]).width());
                });
            }

    接下来,您需要创建两个表,注意头表应该有一个额外的td,以便在顶部表中为滚动条留出空间,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     <table id="headertable1" class="input-cells table-striped">
            <thead>
                <tr style="background-color:darkgray;color:white;"><th>header1</th><th>header2</th><th>header3</th><th>header4</th><th>header5</th><th>header6</th><th></th></tr>
            </thead>
         </table>
       
            <table id="basetable1" class="input-cells table-striped">
                <tbody >
                    <tr>
                        <td>testdata</td>
                        <td>2</td>
                        <td>3</td>
                        <td>4</span></td>
                        <td>55555555555555</td>
                        <td>test</td></tr>
                </tbody>
            </table>

    然后执行以下操作:

    1
    2
    3
    4
            setHeaderTableWidth('headertable1', 'basetable1');
            $(window).resize(function () {
                setHeaderTableWidth('headertable1', 'basetable1');
            });

    这是我在StackOverflow上发现的唯一解决方案,该解决方案可以解决许多已发布的类似问题,并且可以在所有情况下使用。

    例如,我尝试了不适用于durandal的jQuery stickytables插件,以及此处的Google Code项目https://code.google.com/p/js-scroll-table-header/issues/detail?id=2

    其他涉及克隆表的解决方案,性能差或无法正常工作在所有情况下均不起作用。

    不需要这些过于复杂的解决方案。只需像下面的示例一样制作两个表,然后像这里所述的那样调用setHeaderTableWidth函数,即可完成工作。

    如果这对您不起作用,则可能是您正在使用CSS box-sizing属性,需要正确设置它。偶然弄乱CSS内容很容易。有很多事情可能会出错,因此请注意/小心。这种方法对我有用。


    这是我们最终使用的解决方案(为了处理某些极端情况和旧版本的InternetExplorer,我们最终还淡出了滚动条的标题栏,然后在滚动结束时淡出了标题栏,但是在Firefox和WebKit浏览器中,解决方案是可行的,它假设有边界崩溃:崩溃。

    该解决方案的关键是,一旦应用了边框折叠,CSS转换就可以在标头上工作,因此只需拦截滚动事件并正确设置转换即可。您无需重复任何操作。缺少在浏览器中正确实现的这种行为,很难想象会有一个更轻便的解决方案。

    JSFiddle:http://jsfiddle.net/podperson/tH9VU/2/

    它实现为一个简单的jQuery插件。您只需通过$('thead')。sticky()之类的电话使thead变得很粘,它们就会在周围徘徊。它适用于页面上的多个表以及位于大表中间的头部。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    $.fn.sticky = function(){
        $(this).each( function(){
            var thead = $(this),
                tbody = thead.next('tbody');

            updateHeaderPosition();

            function updateHeaderPosition(){
                if(
                    thead.offset().top < $(document).scrollTop()
                    && tbody.offset().top + tbody.height() > $(document).scrollTop()
                ){
                    var tr = tbody.find('tr').last(),
                        y = tr.offset().top - thead.height() < $(document).scrollTop()
                            ? tr.offset().top - thead.height() - thead.offset().top
                            : $(document).scrollTop() - thead.offset().top;

                    thead.find('th').css({
                        'z-index': 100,
                        'transform': 'translateY(' + y + 'px)',
                        '-webkit-transform': 'translateY(' + y + 'px)'
                    });
                } else {
                    thead.find('th').css({
                        'transform': 'none',
                        '-webkit-transform': 'none'
                    });
                }
            }

            // See http://www.quirksmode.org/dom/events/scroll.html
            $(window).on('scroll', updateHeaderPosition);
        });
    }

    $('thead').sticky();


    我喜欢马克西米利安·希尔斯(Maximillian Hils)的回答,但遇到了一些问题:

  • 除非将变换应用于Edge,否则变换在Edge或IE中不起作用
  • 在Edge和IE中滚动时标题闪烁
  • 我的表是使用ajax加载的,所以我想附加到窗口滚动事件,而不是包装器的滚动事件
  • 为了摆脱闪烁,我使用超时来等待用户完成滚动,然后应用转换-因此在滚动过程中标题不可见。

    我也使用jQuery编写了此代码,其优点之一是jQuery应该为您处理供应商前缀

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
        var isScrolling, lastTop, lastLeft, isLeftHidden, isTopHidden;

        //Scroll events don't bubble https://stackoverflow.com/a/19375645/150342
        //so can't use $(document).on("scroll",".table-container-fixed", function (e) {
        document.addEventListener('scroll', function (event) {
            var $container = $(event.target);
            if (!$container.hasClass("table-container-fixed"))
                return;    

            //transform needs to be applied to th for Edge and IE
            //in this example I am also fixing the leftmost column
            var $topLeftCell = $container.find('table:first > thead > tr > th:first');
            var $headerCells = $topLeftCell.siblings();
            var $columnCells = $container
               .find('table:first > tbody > tr > td:first-child, ' +
                     'table:first > tfoot > tr > td:first-child');

            //hide the cells while returning otherwise they show on top of the data
            if (!isLeftHidden) {
                var currentLeft = $container.scrollLeft();
                if (currentLeft < lastLeft) {
                    //scrolling left
                    isLeftHidden = true;
                    $topLeftCell.css('visibility', 'hidden');
                    $columnCells.css('visibility', 'hidden');
                }
                lastLeft = currentLeft;
            }

            if (!isTopHidden) {
                var currentTop = $container.scrollTop();
                if (currentTop < lastTop) {
                    //scrolling up
                    isTopHidden = true;
                    $topLeftCell.css('visibility', 'hidden');
                    $headerCells.css('visibility', 'hidden');
                }
                lastTop = currentTop;
            }

            // Using timeout to delay transform until user stops scrolling
            // Clear timeout while scrolling
            window.clearTimeout(isScrolling);

            // Set a timeout to run after scrolling ends
            isScrolling = setTimeout(function () {
                //move the table cells.
                var x = $container.scrollLeft();
                var y = $container.scrollTop();

                $topLeftCell.css('transform', 'translate(' + x + 'px, ' + y + 'px)');
                $headerCells.css('transform', 'translateY(' + y + 'px)');
                $columnCells.css('transform', 'translateX(' + x + 'px)');

                isTopHidden = isLeftHidden = false;
                $topLeftCell.css('visibility', 'inherit');
                $headerCells.css('visibility', 'inherit');
                $columnCells.css('visibility', 'inherit');
            }, 100);

        }, true);

    该表包装在具有table-container-fixed类的div中。

    1
    2
    3
    4
    .table-container-fixed{
        overflow: auto;
        height: 400px;
    }

    我将border-collapse设置为单独的,因为否则会在翻译过程中丢失边框,并且我删除了表格上的边框以阻止内容显示在滚动过程中边框刚好位于其上方的单元格上方。

    1
    2
    3
    4
    .table-container-fixed > table {
       border-collapse: separate;
       border:none;
    }

    我将th背景设置为白色以覆盖下面的单元格,并添加了与表格边框匹配的边框-使用Bootstrap设置样式并滚动到视图之外。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     .table-container-fixed > table > thead > tr > th {
            border-top: 1px solid #ddd !important;
            background-color: white;        
            z-index: 10;
            position: relative;/*to make z-index work*/
        }

                .table-container-fixed > table > thead > tr > th:first-child {
                    z-index: 20;
                }

    .table-container-fixed > table > tbody > tr > td:first-child,
    .table-container-fixed > table > tfoot > tr > td:first-child {
        background-color: white;        
        z-index: 10;
        position: relative;
    }


    使用最新版本的jQuery,并包含以下JavaScript代码。

    1
    2
    3
    $(window).scroll(function(){
      $("id of the div element").offset({top:$(window).scrollTop()});
    });


    我发现了这种解决方法-将表头行移到带有数据的表上方的表中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    <html>
    <head>
        Fixed header
        <style>
            table td {width:75px;}
        </style>
    </head>

    <body>

    <table border="1">
    <tr>
        <td>header 1</td>
        <td>header 2</td>
        <td>header 3</td>
    </tr>
    </table>



    <table border="1">
    <tr>
        <td>row 1 col 1</td>
        <td>row 1 col 2</td>
        <td>row 1 col 3</td>       
    </tr>
    <tr>
        <td>row 2 col 1</td>
        <td>row 2 col 2</td>
        <td>row 2 col 3</td>       
    </tr>
    <tr>
        <td>row 3 col 1</td>
        <td>row 3 col 2</td>
        <td>row 3 col 3</td>       
    </tr>
    <tr>
        <td>row 4 col 1</td>
        <td>row 4 col 2</td>
        <td>row 4 col 3</td>       
    </tr>
    <tr>
        <td>row 5 col 1</td>
        <td>row 5 col 2</td>
        <td>row 5 col 3</td>       
    </tr>
    <tr>
        <td>row 6 col 1</td>
        <td>row 6 col 2</td>
        <td>row 6 col 3</td>       
    </tr>
    </table>



    </body>
    </html>


    通过将StickyTableHeaders jQuery插件应用于表,当您向下滚动时,列标题将停留在视口的顶部。

    例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    $(function () {
        $("table").stickyTableHeaders();
    });

    /*! Copyright (c) 2011 by Jonas Mosbech - https://github.com/jmosbech/StickyTableHeaders
        MIT license info: https://github.com/jmosbech/StickyTableHeaders/blob/master/license.txt */


    ;
    (function ($, window, undefined) {
        'use strict';

        var name = 'stickyTableHeaders',
            id = 0,
            defaults = {
                fixedOffset: 0,
                leftOffset: 0,
                marginTop: 0,
                scrollableArea: window
            };

        function Plugin(el, options) {
            // To avoid scope issues, use 'base' instead of 'this'
            // to reference this class from internal events and functions.
            var base = this;

            // Access to jQuery and DOM versions of element
            base.$el = $(el);
            base.el = el;
            base.id = id++;
            base.$window = $(window);
            base.$document = $(document);

            // Listen for destroyed, call teardown
            base.$el.bind('destroyed',
            $.proxy(base.teardown, base));

            // Cache DOM refs for performance reasons
            base.$clonedHeader = null;
            base.$originalHeader = null;

            // Keep track of state
            base.isSticky = false;
            base.hasBeenSticky = false;
            base.leftOffset = null;
            base.topOffset = null;

            base.init = function () {
                base.$el.each(function () {
                    var $this = $(this);

                    // remove padding on <table> to fix issue #7
                    $this.css('padding', 0);

                    base.$originalHeader = $('thead:first', this);
                    base.$clonedHeader = base.$originalHeader.clone();
                    $this.trigger('clonedHeader.' + name, [base.$clonedHeader]);

                    base.$clonedHeader.addClass('tableFloatingHeader');
                    base.$clonedHeader.css('display', 'none');

                    base.$originalHeader.addClass('tableFloatingHeaderOriginal');

                    base.$originalHeader.after(base.$clonedHeader);

                    base.$printStyle = $('<style type="text/css" media="print">' +
                        '.tableFloatingHeader{display:none !important;}' +
                        '.tableFloatingHeaderOriginal{position:static !important;}' +
                        '</style>');
                    $('head').append(base.$printStyle);
                });

                base.setOptions(options);
                base.updateWidth();
                base.toggleHeaders();
                base.bind();
            };

            base.destroy = function () {
                base.$el.unbind('destroyed', base.teardown);
                base.teardown();
            };

            base.teardown = function () {
                if (base.isSticky) {
                    base.$originalHeader.css('position', 'static');
                }
                $.removeData(base.el, 'plugin_' + name);
                base.unbind();

                base.$clonedHeader.remove();
                base.$originalHeader.removeClass('tableFloatingHeaderOriginal');
                base.$originalHeader.css('visibility', 'visible');
                base.$printStyle.remove();

                base.el = null;
                base.$el = null;
            };

            base.bind = function () {
                base.$scrollableArea.on('scroll.' + name, base.toggleHeaders);
                if (!base.isWindowScrolling) {
                    base.$window.on('scroll.' + name + base.id, base.setPositionValues);
                    base.$window.on('resize.' + name + base.id, base.toggleHeaders);
                }
                base.$scrollableArea.on('resize.' + name, base.toggleHeaders);
                base.$scrollableArea.on('resize.' + name, base.updateWidth);
            };

            base.unbind = function () {
                // unbind window events by specifying handle so we don't remove too much
                base.$scrollableArea.off('.' + name, base.toggleHeaders);
                if (!base.isWindowScrolling) {
                    base.$window.off('.' + name + base.id, base.setPositionValues);
                    base.$window.off('.' + name + base.id, base.toggleHeaders);
                }
                base.$scrollableArea.off('.' + name, base.updateWidth);
            };

            base.toggleHeaders = function () {
                if (base.$el) {
                    base.$el.each(function () {
                        var $this = $(this),
                            newLeft,
                            newTopOffset = base.isWindowScrolling ? (
                            isNaN(base.options.fixedOffset) ? base.options.fixedOffset.outerHeight() : base.options.fixedOffset) : base.$scrollableArea.offset().top + (!isNaN(base.options.fixedOffset) ? base.options.fixedOffset : 0),
                            offset = $this.offset(),

                            scrollTop = base.$scrollableArea.scrollTop() + newTopOffset,
                            scrollLeft = base.$scrollableArea.scrollLeft(),

                            scrolledPastTop = base.isWindowScrolling ? scrollTop > offset.top : newTopOffset > offset.top,
                            notScrolledPastBottom = (base.isWindowScrolling ? scrollTop : 0) < (offset.top + $this.height() - base.$clonedHeader.height() - (base.isWindowScrolling ? 0 : newTopOffset));

                        if (scrolledPastTop && notScrolledPastBottom) {
                            newLeft = offset.left - scrollLeft + base.options.leftOffset;
                            base.$originalHeader.css({
                                'position': 'fixed',
                                    'margin-top': base.options.marginTop,
                                    'left': newLeft,
                                    'z-index': 3 // #18: opacity bug
                            });
                            base.leftOffset = newLeft;
                            base.topOffset = newTopOffset;
                            base.$clonedHeader.css('display', '');
                            if (!base.isSticky) {
                                base.isSticky = true;
                                // make sure the width is correct: the user might have resized the browser while in static mode
                                base.updateWidth();
                            }
                            base.setPositionValues();
                        } else if (base.isSticky) {
                            base.$originalHeader.css('position', 'static');
                            base.$clonedHeader.css('display', 'none');
                            base.isSticky = false;
                            base.resetWidth($('td,th', base.$clonedHeader), $('td,th', base.$originalHeader));
                        }
                    });
                }
            };

            base.setPositionValues = function () {
                var winScrollTop = base.$window.scrollTop(),
                    winScrollLeft = base.$window.scrollLeft();
                if (!base.isSticky || winScrollTop < 0 || winScrollTop + base.$window.height() > base.$document.height() || winScrollLeft < 0 || winScrollLeft + base.$window.width() > base.$document.width()) {
                    return;
                }
                base.$originalHeader.css({
                    'top': base.topOffset - (base.isWindowScrolling ? 0 : winScrollTop),
                        'left': base.leftOffset - (base.isWindowScrolling ? 0 : winScrollLeft)
                });
            };

            base.updateWidth = function () {
                if (!base.isSticky) {
                    return;
                }
                // Copy cell widths from clone
                if (!base.$originalHeaderCells) {
                    base.$originalHeaderCells = $('th,td', base.$originalHeader);
                }
                if (!base.$clonedHeaderCells) {
                    base.$clonedHeaderCells = $('th,td', base.$clonedHeader);
                }
                var cellWidths = base.getWidth(base.$clonedHeaderCells);
                base.setWidth(cellWidths, base.$clonedHeaderCells, base.$originalHeaderCells);

                // Copy row width from whole table
                base.$originalHeader.css('width', base.$clonedHeader.width());
            };

            base.getWidth = function ($clonedHeaders) {
                var widths = [];
                $clonedHeaders.each(function (index) {
                    var width, $this = $(this);

                    if ($this.css('box-sizing') === 'border-box') {
                        width = $this[0].getBoundingClientRect().width; // #39: border-box bug
                    } else {
                        var $origTh = $('th', base.$originalHeader);
                        if ($origTh.css('border-collapse') === 'collapse') {
                            if (window.getComputedStyle) {
                                width = parseFloat(window.getComputedStyle(this, null).width);
                            } else {
                                // ie8 only
                                var leftPadding = parseFloat($this.css('padding-left'));
                                var rightPadding = parseFloat($this.css('padding-right'));
                                // Needs more investigation - this is assuming constant border around this cell and it's neighbours.
                                var border = parseFloat($this.css('border-width'));
                                width = $this.outerWidth() - leftPadding - rightPadding - border;
                            }
                        } else {
                            width = $this.width();
                        }
                    }

                    widths[index] = width;
                });
                return widths;
            };

            base.setWidth = function (widths, $clonedHeaders, $origHeaders) {
                $clonedHeaders.each(function (index) {
                    var width = widths[index];
                    $origHeaders.eq(index).css({
                        'min-width': width,
                            'max-width': width
                    });
                });
            };

            base.resetWidth = function ($clonedHeaders, $origHeaders) {
                $clonedHeaders.each(function (index) {
                    var $this = $(this);
                    $origHeaders.eq(index).css({
                        'min-width': $this.css('min-width'),
                            'max-width': $this.css('max-width')
                    });
                });
            };

            base.setOptions = function (options) {
                base.options = $.extend({}, defaults, options);
                base.$scrollableArea = $(base.options.scrollableArea);
                base.isWindowScrolling = base.$scrollableArea[0] === window;
            };

            base.updateOptions = function (options) {
                base.setOptions(options);
                // scrollableArea might have changed
                base.unbind();
                base.bind();
                base.updateWidth();
                base.toggleHeaders();
            };

            // Run initializer
            base.init();
        }

        // A plugin wrapper around the constructor,
        // preventing against multiple instantiations
        $.fn[name] = function (options) {
            return this.each(function () {
                var instance = $.data(this, 'plugin_' + name);
                if (instance) {
                    if (typeof options === 'string') {
                        instance[options].apply(instance);
                    } else {
                        instance.updateOptions(options);
                    }
                } else if (options !== 'destroy') {
                    $.data(this, 'plugin_' + name, new Plugin(this, options));
                }
            });
        };

    })(jQuery, window);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    body {
        margin: 0 auto;
        padding: 0 20px;
        font-family: Arial, Helvetica, sans-serif;
        font-size: 11px;
        color: #555;
    }
    table {
        border: 0;
        padding: 0;
        margin: 0 0 20px 0;
        border-collapse: collapse;
    }
    th {
        padding: 5px;
        /* NOTE: th padding must be set explicitly in order to support IE */
        text-align: right;
        font-weight:bold;
        line-height: 2em;
        color: #FFF;
        background-color: #555;
    }
    tbody td {
        padding: 10px;
        line-height: 18px;
        border-top: 1px solid #E0E0E0;
    }
    tbody tr:nth-child(2n) {
        background-color: #F7F7F7;
    }
    tbody tr:hover {
        background-color: #EEEEEE;
    }
    td {
        text-align: right;
    }
    td:first-child, th:first-child {
        text-align: left;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
    some really really wide content goes here
    <table>
        <thead>
            <tr>
                <th colspan="9">Companies listed on NASDAQ OMX Copenhagen.</th>
            </tr>
            <tr>
                <th>Full name</th>
                <th>CCY</th>
                <th>Last</th>
                <th>+/-</th>
                <th>%</th>
                <th>Bid</th>
                <th>Ask</th>
                <th>Volume</th>
                <th>Turnover</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>A.P. M?ller...</td>
                <td>DKK</td>
                <td>33,220.00</td>
                <td>760</td>
                <td>2.34</td>
                <td>33,140.00</td>
                <td>33,220.00</td>
                <td>594</td>
                <td>19,791,910</td>
            </tr>
            <tr>
                <td>A.P. M?ller...</td>
                <td>DKK</td>
                <td>34,620.00</td>
                <td>640</td>
                <td>1.88</td>
                <td>34,620.00</td>
                <td>34,700.00</td>
                <td>9,954</td>
                <td>346,530,246</td>
            </tr>
            <tr>
                <td>Carlsberg A</td>
                <td>DKK</td>
                <td>380</td>
                <td>0</td>
                <td>0</td>
                <td>371</td>
                <td>391.5</td>
                <td>6</td>
                <td>2,280</td>
            </tr>
            <tr>
                <td>Carlsberg B</td>
                <td>DKK</td>
                <td>364.4</td>
                <td>8.6</td>
                <td>2.42</td>
                <td>363</td>
                <td>364.4</td>
                <td>636,267</td>
                <td>228,530,601</td>
            </tr>
            <tr>
                <td>Chr. Hansen...</td>
                <td>DKK</td>
                <td>114.5</td>
                <td>-1.6</td>
                <td>-1.38</td>
                <td>114.2</td>
                <td>114.5</td>
                <td>141,822</td>
                <td>16,311,454</td>
            </tr>
            <tr>
                <td>Coloplast B</td>
                <td>DKK</td>
                <td>809.5</td>
                <td>11</td>
                <td>1.38</td>
                <td>809</td>
                <td>809.5</td>
                <td>85,840</td>
                <td>69,363,301</td>
            </tr>
            <tr>
                <td>D/S Norden</td>
                <td>DKK</td>
                <td>155</td>
                <td>-1.5</td>
                <td>-0.96</td>
                <td>155</td>
                <td>155.1</td>
                <td>51,681</td>
                <td>8,037,225</td>
            </tr>
            <tr>
                <td>Danske Bank</td>
                <td>DKK</td>
                <td>69.05</td>
                <td>2.55</td>
                <td>3.83</td>
                <td>69.05</td>
                <td>69.2</td>
                <td>1,723,719</td>
                <td>115,348,068</td>
            </tr>
            <tr>
                <td>DSV</td>
                <td>DKK</td>
                <td>105.4</td>
                <td>0.2</td>
                <td>0.19</td>
                <td>105.2</td>
                <td>105.4</td>
                <td>674,873</td>
                <td>71,575,035</td>
            </tr>
            <tr>
                <td>FLSmidth & Co.</td>
                <td>DKK</td>
                <td>295.8</td>
                <td>-1.8</td>
                <td>-0.6</td>
                <td>295.1</td>
                <td>295.8</td>
                <td>341,263</td>
                <td>100,301,032</td>
            </tr>
            <tr>
                <td>G4S plc</td>
                <td>DKK</td>
                <td>22.53</td>
                <td>0.05</td>
                <td>0.22</td>
                <td>22.53</td>
                <td>22.57</td>
                <td>190,920</td>
                <td>4,338,150</td>
            </tr>
            <tr>
                <td>Jyske Bank</td>
                <td>DKK</td>
                <td>144.2</td>
                <td>1.4</td>
                <td>0.98</td>
                <td>142.8</td>
                <td>144.2</td>
                <td>78,163</td>
                <td>11,104,874</td>
            </tr>
            <tr>
                <td>K?benhavns ...</td>
                <td>DKK</td>
                <td>1,580.00</td>
                <td>-12</td>
                <td>-0.75</td>
                <td>1,590.00</td>
                <td>1,620.00</td>
                <td>82</td>
                <td>131,110</td>
            </tr>
            <tr>
                <td>Lundbeck</td>
                <td>DKK</td>
                <td>103.4</td>
                <td>-2.5</td>
                <td>-2.36</td>
                <td>103.4</td>
                <td>103.8</td>
                <td>157,162</td>
                <td>16,462,282</td>
            </tr>
            <tr>
                <td>Nordea Bank</td>
                <td>DKK</td>
                <td>43.22</td>
                <td>-0.06</td>
                <td>-0.14</td>
                <td>43.22</td>
                <td>43.25</td>
                <td>167,520</td>
                <td>7,310,143</td>
            </tr>
            <tr>
                <td>Novo Nordisk B</td>
                <td>DKK</td>
                <td>552.5</td>
                <td>-3.5</td>
                <td>-0.63</td>
                <td>550.5</td>
                <td>552.5</td>
                <td>843,533</td>
                <td>463,962,375</td>
            </tr>
            <tr>
                <td>Novozymes B</td>
                <td>DKK</td>
                <td>805.5</td>
                <td>5.5</td>
                <td>0.69</td>
                <td>805</td>
                <td>805.5</td>
                <td>152,188</td>
                <td>121,746,199</td>
            </tr>
            <tr>
                <td>Pandora</td>
                <td>DKK</td>
                <td>39.04</td>
                <td>0.94</td>
                <td>2.47</td>
                <td>38.8</td>
                <td>39.04</td>
                <td>350,965</td>
                <td>13,611,838</td>
            </tr>
            <tr>
                <td>Rockwool In...</td>
                <td>DKK</td>
                <td>492</td>
                <td>0</td>
                <td>0</td>
                <td>482</td>
                <td>492</td>
                <td></td>
                <td></td>
            </tr>
            <tr>
                <td>Rockwool In...</td>
                <td>DKK</td>
                <td>468</td>
                <td>12</td>
                <td>2.63</td>
                <td>465.2</td>
                <td>468</td>
                <td>9,885</td>
                <td>4,623,850</td>
            </tr>
            <tr>
                <td>Sydbank</td>
                <td>DKK</td>
                <td>95</td>
                <td>0.05</td>
                <td>0.05</td>
                <td>94.7</td>
                <td>95</td>
                <td>103,438</td>
                <td>9,802,899</td>
            </tr>
            <tr>
                <td>TDC</td>
                <td>DKK</td>
                <td>43.6</td>
                <td>0.13</td>
                <td>0.3</td>
                <td>43.5</td>
                <td>43.6</td>
                <td>845,110</td>
                <td>36,785,339</td>
            </tr>
            <tr>
                <td>Topdanmark</td>
                <td>DKK</td>
                <td>854</td>
                <td>13.5</td>
                <td>1.61</td>
                <td>854</td>
                <td>855</td>
                <td>38,679</td>
                <td>32,737,678</td>
            </tr>
            <tr>
                <td>Tryg</td>
                <td>DKK</td>
                <td>290.4</td>
                <td>0.3</td>
                <td>0.1</td>
                <td>290</td>
                <td>290.4</td>
                <td>94,587</td>
                <td>27,537,247</td>
            </tr>
            <tr>
                <td>Vestas Wind...</td>
                <td>DKK</td>
                <td>90.15</td>
                <td>-4.2</td>
                <td>-4.45</td>
                <td>90.1</td>
                <td>90.15</td>
                <td>1,317,313</td>
                <td>121,064,314</td>
            </tr>
            <tr>
                <td>William Dem...</td>
                <td>DKK</td>
                <td>417.6</td>
                <td>0.1</td>
                <td>0.02</td>
                <td>417</td>
                <td>417.6</td>
                <td>64,242</td>
                <td>26,859,554</td>
            </tr>
        </tbody>
    </table>
    lots of content down here...


    这不是固定标题行的精确解决方案,但我创建了一种相当巧妙的方法,可以在整个长表中重复标题行,但仍保持排序的能力。

    这个简洁的小选项需要jQuery tablesorter插件。运作方式如下:

    的HTML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    <table class="tablesorter boxlist" id="pmtable">
        <thead class="fixedheader">
            <tr class="boxheadrow">
                <th width="70px" class="header">Job Number</th>
                <th width="10px" class="header">Pri</th>
                <th width="70px" class="header">CLLI</th>
                <th width="35px" class="header">Market</th>
                <th width="35px" class="header">Job Status</th>
                <th width="65px" class="header">Technology</th>
                <th width="95px;" class="header headerSortDown">MEI</th>
                <th width="95px" class="header">TEO Writer</th>
                <th width="75px" class="header">Quote Due</th>
                <th width="100px" class="header">Engineer</th>
                <th width="75px" class="header">ML Due</th>
                <th width="75px" class="header">ML Complete</th>
                <th width="75px" class="header">SPEC Due</th>
                <th width="75px" class="header">SPEC Complete</th>
                <th width="100px" class="header">Install Supervisor</th>
                <th width="75px" class="header">MasTec OJD</th>
                <th width="75px" class="header">Install Start</th>
                <th width="30px" class="header">Install Hours</th>
                <th width="75px" class="header">Revised CRCD</th>
                <th width="75px" class="header">Latest Ship-To-Site</th>
                <th width="30px" class="header">Total Parts</th>
                <th width="30px" class="header">OEM Rcvd</th>
                <th width="30px" class="header">Minor Rcvd</th>
                <th width="30px" class="header">Total Received</th>
                <th width="30px" class="header">% On Site</th>
                <th width="60px" class="header">Actions</th>
            </tr>
        </thead>
            <tbody class="scrollable">
                <tr data-job_id="3548" data-ml_id="" class="odd">
                    <td class="c black">FL-8-RG9UP</td>
                    <td data-pri="2" class="priority c yellow">M</td>
                    <td class="c">FTLDFLOV</td>
                    <td class="c">SFL</td>
                    <td class="c">NOI</td>
                    <td class="c">TRANSPORT</td>
                    <td class="c"></td>
                    <td class="c">Chris Byrd</td>
                    <td class="c">Apr 13, 2013</td>
                    <td class="c">Kris Hall</td>
                    <td class="c">May 20, 2013</td>
                    <td class="c">May 20, 2013</td>
                    <td class="c">Jun 5, 2013</td>
                    <td class="c">Jun 7, 2013</td>
                    <td class="c">Joseph Fitz</td>
                    <td class="c">Jun 10, 2013</td>
                    <td class="c">TBD</td>
                    <td class="c">123</td>
                    <td class="c revised_crcd"><input readonly="true" name="revised_crcd" value="Jul 26, 2013" type="text" size="12" class="smInput r_crcd c hasDatepicker" id="dp1377194058616"></td>
                    <td class="c">TBD</td>
                    <td class="c">N/A</td>
                    <td class="c">N/A</td>
                    <td class="c">N/A</td>
                    <td class="c">N/A</td>
                    <td class="c">N/A</td>
                    <td class="actions"><span style="float:left;" class="ui-icon ui-icon-folder-open editJob" title="View this job" s="" details'=""></span></td>
                </tr>
                <tr data-job_id="4264" data-ml_id="2959" class="even">
                    <td class="c black">MTS13009SF</td>
                    <td data-pri="2" class="priority c yellow">M</td>
                    <td class="c">OJUSFLTL</td>
                    <td class="c">SFL</td>
                    <td class="c">NOI</td>
                    <td class="c">TRANSPORT</td>
                    <td class="c"></td>
                    <td class="c">DeMarcus Stewart</td>
                    <td class="c">May 22, 2013</td>
                    <td class="c">Ryan Alsobrook</td>
                    <td class="c">Jun 19, 2013</td>
                    <td class="c">Jun 27, 2013</td>
                    <td class="c">Jun 19, 2013</td>
                    <td class="c">Jul 4, 2013</td>
                    <td class="c">Randy Williams</td>
                    <td class="c">Jun 21, 2013</td>
                    <td class="c">TBD</td>
                    <td class="c">95</td>
                    <td class="c revised_crcd"><input readonly="true" name="revised_crcd" value="Aug 9, 2013" type="text" size="12" class="smInput r_crcd c hasDatepicker" id="dp1377194058632"></td><td class="c">TBD</td>
                    <td class="c">0</td>
                    <td class="c">0.00%</td>
                    <td class="c">0.00%</td>
                    <td class="c">0.00%</td>
                    <td class="c">0.00%</td>
                    <td class="actions"><span style="float:left;" class="ui-icon ui-icon-folder-open editJob" title="View this job" s="" details'
    =""></span><input style="float:left;" type="hidden" name="req_ship" class="reqShip hasDatepicker" id="dp1377194058464"><span style="float:left;" class="ui-icon ui-icon-calendar requestShip" title="Schedule this job for shipping"></span><span class="ui-icon ui-icon-info viewOrderInfo" style="float:left;" title="Show material details for this order"></span></td>
                </tr>
                .
                .
                .
                .
                <tr class="boxheadrow repeated-header">
                    <th width="70px" class="header">Job Number</th>
                    <th width="10px" class="header">Pri</th>
                    <th width="70px" class="header">CLLI</th>
                    <th width="35px" class="header">Market</th>
                    <th width="35px" class="header">Job Status</th>
                    <th width="65px" class="header">Technology</th>
                    <th width="95px;" class="header">MEI</th>
                    <th width="95px" class="header">TEO Writer</th>
                    <th width="75px" class="header">Quote Due</th>
                    <th width="100px" class="header">Engineer</th>
                    <th width="75px" class="header">ML Due</th>
                    <th width="75px" class="header">ML Complete</th>
                    <th width="75px" class="header">SPEC Due</th>
                    <th width="75px" class="header">SPEC Complete</th>
                    <th width="100px" class="header">Install Supervisor</th>
                    <th width="75px" class="header">MasTec OJD</th>
                    <th width="75px" class="header">Install Start</th>
                    <th width="30px" class="header">Install Hours</th>
                    <th width="75px" class="header">Revised CRCD</th>
                    <th width="75px" class="header">Latest Ship-To-Site</th>
                    <th width="30px" class="header">Total Parts</th>
                    <th width="30px" class="header">OEM Rcvd</th>
                    <th width="30px" class="header">Minor Rcvd</th>
                    <th width="30px" class="header">Total Received</th>
                    <th width="30px" class="header">% On Site</th>
                    <th width="60px" class="header">Actions</th>
                </tr>

    显然,我的表具有比这更多的行。确切地说是193,但您可以看到标题行重复的位置。重复标题行是通过以下功能设置的:

    jQuery的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // Clone the original header row and add the"repeated-header" class
    var tblHeader = $('tr.boxheadrow').clone().addClass('repeated-header');

    // Add the cloned header with the new class every 34th row (or as you see fit)
    $('tbody tr:odd:nth-of-type(17n)').after(tblHeader);

    // On the 'sortStart' routine, remove all the inserted header rows
    $('#pmtable').bind('sortStart', function() {
        $('.repeated-header').remove();
        // On the 'sortEnd' routine, add back all the header row lines.
    }).bind('sortEnd', function() {
        $('tbody tr:odd:nth-of-type(17n)').after(tblHeader);
    });