繁体   English   中英

如何在可滚动的div中冻结html表的第一列和最后一列?

[英]How do I freeze the first and last columns of an html table in a scrollable div?

我有一个表有一个标题行,但也有一个标题列和一个总列,其中有几列。

像这样的东西:

Name    Score 1    Score 2  ...  Total
--------------------------------------
John       5          6            86
Will       3          7            82
Nick       7          1            74

整个表在固定宽度的可滚动div中定义,因为可能有大量的“Score”行,并且我有一个固定宽度的页面布局。

<div id="tableWrapper" style="overflow-x: auto; width: 500px;">
    <table id="scoreTable">
        ...
    </table>
</div>

我想要的是第一个( Name )和最后一个( Total )列在内部列滚动时保持可见。

谁能帮我这个?

编辑:我的意思是仅水平滚动 - 更改为指定。


更新:我已经为自己解决了这个问题,并在下面发布了答案。 如果您需要更多信息,请告诉我 - 这有点痛苦,我讨厌别人必须重写所有内容。

我可以提出一个有点非正统的解决方案吗?

您如何考虑将'total'列放在'name'列之后,而不是在最后? 这不会避免只需要滚动表的一部分吗?

这不完全是你所要求的,但也许这是一个充分的解决方案,因为替代方案会非常混乱。 (例如,在表格之外放置'total'和'name'列会在不是所有行都具有相同高度时产生对齐问题。你可以用javascript来纠正这个问题,但是你会进入一个全新的世界痛)。

同样从UI的角度来看,'name'和'total'可能是最重要的数据,在这种情况下将它们组合在一起是有意义的,然后是总计的“细分”。 当然,我们似乎有一种直觉,即'总数'应该在它的组成部分之后,但我不认为如果订单被这样颠倒,它会给用户带来太多的混淆(尽管这是一个问题)您,基于您的产品和用户)。

无论如何,需要考虑的事情。

编辑:

以下是一些非正统的解决方案,现在我认为我更了解你的意图:

  1. 分数得分。 给出最近的十个,比如说和总数,以及一次提供10个旧分数的链接
  2. 只提供名称,总计和其他一些有意义的度量,例如mean和sd,然后为每个名称提供一个链接,显示与该名称对应的所有结果。 然后,您还可以提供显示给定分数集的所有结果的链接,以便可以进行不同用户之间的比较。 关键在于您只需要为每个视图提供1维数据,而不是拥有难以处理的2D数据集
  3. 使行可排序(使用jQuery UI很容易),这样如果我想比较Mary和Jane,我可以一个接一个地拖动和放置,所以我不需要继续向左和向右滚动以查看哪些分数对应于哪些名称
  4. 单击时突出显示一行,通过更改背景颜色或类似颜色,再次,这样我就不需要继续向左和向右滚动。

无论如何,你明白了。 也许最好是寻找UI解决方案而不是扭曲的标记解决方案。 最后,我会质疑一次向用户提供如此多的数据是多么重要,它的一部分需要以特定方式滚动才能使数据可读。 也许您正在构建电子表格应用程序,并且您确实需要在单个视图中显示100x100矩阵。 如果没有,你肯定会提出比我分割结果更有创意的方法。

看看这个jQuery插件:

http://fixedheadertable.com/

我已经尝试了一些方法(感谢所有帮助过的人),这就是我用jQuery提出的方法。 它似乎在我测试的所有浏览器中都运行良好。 随意拿它并随意使用它。 对我来说,下一步将把它变成一个可重用的jQuery插件。

摘要:

我开始使用普通表,其中包含所有内容( Id =“ladderTable” ),我写了三个方法 - 一个用于剥离第一列,一个用于剥离最后一列,另一个用于修复行高。

stripFirstColumn方法创建一个新表( Id =“nameTable” ),遍历原始表并取出第一列,并将这些单元格添加到nameTable。

stripLastColumn方法基本上做同样的事情,除了它取出最后一列并将单元格添加到名为totalTable的新表中。

fixHeights方法查看每个表中的每一行,计算最大高度,并将其应用于相关表。

在文档就绪事件中,我按顺序调用了所有三种方法。 请注意,所有三个表都向左浮动,因此它们只是水平堆叠。

HTML结构:

<h1>Current Ladder</h1> 
<div id="nameTableSpan" style="float:left;width:100px;border-right:2px solid gray;"></div> 
<div id="ladderDiv" style="float:left;width:423px;overflow:auto;border:1px solid gray;margin-top:-1px;"> 
    <table id="ladderTable" class="ladderTable">
        <thead> 
            <tr><td>Name</td><td>Round 1</td> ... <td>Round 50</td><td class="scoreTotal">Total</td></tr>
        </thead>
        <tr><td>Bob</td><td>11</td> ... <td>75</td><td>421</td></tr>
           ... (more scores)
    </table>
</div>
<div id="totalTableSpan" style="float:left;width:70px;border-left:2px solid gray;"></div> 

jQuery:

function stripFirstColumn() {                
    // pull out first column:
    var nt = $('<table id="nameTable" cellpadding="3" cellspacing="0" style="width:100px;"></table>');
    $('#ladderTable tr').each(function(i)
    {
        nt.append('<tr><td style="color:'+$(this).children('td:first').css('color')+'">'+$(this).children('td:first').html()+'</td></tr>');
    });
    nt.appendTo('#nameTableSpan');
    // remove original first column
    $('#ladderTable tr').each(function(i)
    {
        $(this).children('td:first').remove();
    });
    $('#nameTable td:first').css('background-color','#8DB4B7');
}

function stripLastColumn() {                
    // pull out last column:
    var nt = $('<table id="totalTable" cellpadding="3" cellspacing="0" style="width:70px;"></table>');
    $('#ladderTable tr').each(function(i)
    {
        nt.append('<tr><td style="color:'+$(this).children('td:last').css('color')+'">'+$(this).children('td:last').html()+'</td></tr>');
    });
    nt.appendTo('#totalTableSpan');
    // remove original last column
    $('#ladderTable tr').each(function(i)
    {
        $(this).children('td:last').remove();
    });
    $('#totalTable td:first').css('background-color','#8DB4B7');
}

function fixHeights() {
    // change heights:
    var curRow = 1;
    $('#ladderTable tr').each(function(i){
        // get heights
        var c1 = $('#nameTable tr:nth-child('+curRow+')').height();    // column 1
        var c2 = $(this).height();    // column 2
        var c3 = $('#totalTable tr:nth-child('+curRow+')').height();    // column 3
        var maxHeight = Math.max(c1, Math.max(c2, c3));

        //$('#log').append('Row '+curRow+' c1=' + c1 +' c2=' + c2 +' c3=' + c3 +'  max height = '+maxHeight+'<br/>');

        // set heights
        //$('#nameTable tr:nth-child('+curRow+')').height(maxHeight);
        $('#nameTable tr:nth-child('+curRow+') td:first').height(maxHeight);
        //$('#log').append('NameTable: '+$('#nameTable tr:nth-child('+curRow+')').height()+'<br/>');
        //$(this).height(maxHeight);
        $(this).children('td:first').height(maxHeight);
        //$('#log').append('MainTable: '+$(this).height()+'<br/>');
        //$('#totalTable tr:nth-child('+curRow+')').height(maxHeight);
        $('#totalTable tr:nth-child('+curRow+') td:first').height(maxHeight);
        //$('#log').append('TotalTable: '+$('#totalTable tr:nth-child('+curRow+')').height()+'<br/>');

        curRow++;
    });

    if ($.browser.msie)
        $('#ladderDiv').height($('#ladderDiv').height()+18);
}

$(document).ready(function() {
    stripFirstColumn();
    stripLastColumn();
    fixHeights();
    $("#ladderDiv").attr('scrollLeft', $("#ladderDiv").attr('scrollWidth'));    // scroll to the last round
});

如果您有任何疑问或者有任何不清楚的地方,我非常乐意提供帮助。

我花了很长时间才发现没有什么东西可以真正重复使用,而且写这个花了更长的时间。 我讨厌别人去找同样的麻烦。

我假设你只想水平滚动它。 否则它可能会与静态列混淆。

你可以将overflow:auto放到内部表格单元格的包含元素上......我不确定浏览器会如何处理这个问题,但是你可以将你想要修复的元素放在thead和tfoot元素中,将滚动部分放在tbody元素中,并将其溢出设置为auto。

如果做不到这一点,您可能需要删除语义并对表格外的左列和右列进行编码。

就个人而言,我会尝试将其编码为尽可能语义,然后使用JavaScript来定位左右列。 没有JavaScript,你应该让它优雅地失败到一个宽表(不知道这会有多困难,因为你说你有一个固定的宽度)

您可以尝试这个(粗略的)jQuery示例将第一列的值放在外面。

var nameTable = '<table id="outside-name-col">
                  <thead>
                   <tr>
                    <th>Name</th>
                   </tr>
                  </thead>
                 <tbody>'; // start making a table for name column only

$('#scoreTable tbody tr').each(function() { // iterate through existing table

   var nameCol = $(this).find(':first'); // get column of index 0, i.e. first

   var cellHeight = nameCol.height(); // get the height of this cell

   $(this).find('td').height(cellHeight); // equalise the height across the row so removing this element will not collapse the height if it is taller than the scores and total       

   nameTable += '<tr><td style="height: ' + cellHeight + 'px">' + nameCol.html() + '</td></tr>'; // append the next row with new height and data

   nameCol.remove(); // remove this cell from the table now it's been placed outside

});

nameTable += '</tbody></table>'; // finish table string


$('#scoreTable').before(nameTable); // insert just before the score table

使用CSS定位它们以正确对齐。 这是未经测试的,但它应该给你一些想法。

它现在还不完整(我只是非常快速地嘲笑它),但这是使用直接HTML的方法。 你想要三个表......两个在<div>之外,一个在<div>之内。 这三个都浮在左边,所以它们都在同一条线上。

表测试

和代码本身:

  <table style="float: left;">
     <tr>
        <td>Name</td>
     </tr>
     <tr>
        <td>John</td>
     </tr>
     <tr>
        <td>Will</td>
     </tr>
  </table>
  <div id="tableWrapper" style="overflow-x: auto; width: 500px;float:left;padding-bottom: 10px;">
      <table>
        <tr>
           <td>Score1</td>
           <td>Score2</td>
           ...
        </tr>
        <tr>
           <td>5</td>
           <td>6</td>
           ...
        </tr>
        <tr>
           <td>3</td>
           <td>7</td>
           ...
        </tr>
        <tr>
           <td>7</td>
           <td>1</td>
           ...
        </tr>
      </table>
  </div>
  <table style="float: left;">
     <tr>
        <td>Total</td>
     </tr>
     <tr>
        <td>86</td>
     </tr>
     <tr>
        <td>82</td>
     </tr>
  </table>

注意:div上的填充底部是这样的,滚动条不会掩盖IE中的表格。 此外,我必须解决的错误是如何指定中间表内的标题元素的宽度。 出于某种原因,指定width =“”属性不起作用。 因此,如果标题元素的文本太宽(并且中断到另一行),则布局被打破(关闭一行)

你的意思是水平滚动吗?

如果要实现水平滚动,则可以使用3个容器。

  1. 对于第一列(名称)
  2. 对于要滚动的列。 将此容器的overflow-x样式设置为auto
  3. 最后一栏(总计)

滚动表的内容是一个有问题的问题,因为没有简单且浏览器安全的解决方案来实现这一点。

最好和最安全的方法需要JavaScript。 您可以使用我使用的这种技术轻松实现水平滚动(免费提供)。 您可以轻松地将其转换为您的问题:

1)我做了3个表

2)放置中间表,将数据保存在DIV容器中

3)将DIV样式设置为overflow:auto

4)给出页眉和页脚表格和每个宽度为100%的div

5)用另一个div包围所有内容来控制整个表格的宽度

6)确保所有三个表中的列数匹配,并且所有三个表都有关于填充,边距和边框的相同样式

现在有趣的部分:

6)在该表构造的最后一个元素下面,写一个javascript块(或从文件中包含它)

7)编写一个连续查看每一列的函数(使用for循环),从第一列开始。 在该循环的每次迭代中,检查当前列中前两个表的td单元格。 检查哪个是较大的并将其分配给较小的td单元格样式。 您可能还想将该值应用于页脚表。

8)调用该函数。 您可能希望在间隔或特殊事件发生时执行此操作,例如单元格中的新数据(例如,如果使用ajax)。

注意:如果您进行水平滚动,则会同步列大小。 但是,您必须将页眉和页脚表的滚动位置与内容表同步。 或者你只需​​让整个div水平滚动整个东西,但不是垂直滚动。 这将是包含数据表的DIV的工作。

这种技术在非常复杂的甘特图项目中的所有主要浏览器中都运行良好。

注意:您可以轻松地以90度旋转方式考虑该概念,以便在滚动时修复第一个和最后一个标题列。

编辑:这是我的代码库中的另一个示例,它可以帮助您获得解决方案:

var left_td = document.getElementById("left_td");
var right_td = document.getElementById("right_td");
var contentDiv = document.getElementById("contentDiv");
window.setInterval(function(){
    var left_td_width = Math.round((parseInt(contentDIV.offsetWidth) - 120) / 2);
    var right_td_width = (parseInt(contentDIV.offsetWidth) - left_td_width - 120;

    left_td.style.width = left_td_width + "px";
    right_td.style.width = right_td_width + "px";
}, 25);

此代码执行以下操作:确保具有3列的表始终如下:第一列和最后一列具有相同的大小,中间列的宽度为120像素。 当然这不会直接适用于您的特殊问题,但它可能会为您提供通过JavaScript进行动态表操作的起点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM