"一套解决方案,用于固定 Grid 的标题行,为什么不呢?"






4.91/5 (10投票s)
通过固定标题行来增强表格/网格的可用性和外观。让我们一起来探索一下。
简介
HTML 中的表格结构和 ASP.NET 中的 GridView 提供了各种智能的数据渲染方式。  但我一直在寻找一个问题的答案,那就是如何固定标题行以便在滚动页面时轻松跟踪数据。不幸的是,GridView 控件本身不提供这样的功能。我在网上搜索解决方案,但没有一个让我满意。因此,我决定开发一个库来支持此功能。 以下是结果: 


背景  
客户端的“滚动”事件处理是此技术的核心。当页面滚动时,标题行即将超出视线,整个行会从网格中分离出来,然后浮动在浏览器顶部。相反,当标题行回到屏幕视图下方时,它会像什么都没发生一样重新加入网格。
工作原理如下:
 
 
这里解释了标题行如何从网格中分离:

使用代码
固定标题行是一件棘手的事情。它其实很简单。使用 JQuery 来挂钩事件并时刻关注标题行位置的变化。实现方式如下:
<script type="text/javascript">
    var gridview_header_top_position = 0;
    $(document).ready(function() {
        $(window).scroll(function() 
        {
            if ($(window).scrollTop() >= top_position_of_header_row) 
            {
                //Disconnect the header row from grid and push it up on top of browser:        
                //For example: jHeaderRow.css('position', 'fixed');
            }
            else
            {
                //Put it back where the orginal position belongs
                //For example: jHeaderRow.css('position', '');
                ...
            }
        });
    }); 
</script>  上面的代码片段不会产生服务器往返的开销。但如果您不希望网页因响应每个滚动事件而变得迟钝,请在编写脚本时务必小心。为了优化性能,请定义一些变量来存储不变或很少更改的数据,例如:网格视图的位置、标题行的克隆副本...
请注意,每个标题单元格的样式在与网格分离后会丢失。因此,在分离标题单元格时应保留“可见”属性(边框、填充、字体...)。
浏览器兼容性
| 一项艰巨的任务是让您的网页在各种浏览器中平稳运行并兼容,从而使其看起来和感觉都像在使用相同的浏览器一样。显然,为了让它能应对所有挑战,我们必须对代码进行大量微调。 上述解决方案在 Firefox、Opera 和 Chrome 中运行得相当好。对于 Safari 和 Flock,在重新组合碎片(标题行和数据/页脚行)后布局会损坏。对于 IE 浏览器,版本 8.0 及以上版本运行良好。对于 IE 7.0、6.0 或更低版本,效果不佳。IE 6 不支持“fixed”定位。这需要使用一些 CSS 技巧来实现。但 CSS 技巧不是一个好主意,因为其他不相关的部分可能会受到影响。那么,为什么我们要为这些问题付出巨大的努力呢?建议是,对于 IE 6.0 和 7.0,如果您不想承担巨大的成本,可以保留网格标题不固定。 | 
测试用例
有 3 种主要场景可能一开始没有注意到:
测试用例 #1:当网格标题固定时,标题行和数据行的单元格不成比例。如下面的图片所示:

此 bug 发生在设置 GridView 控件的单元格样式时。这是固定标题本身的问题,当整个标题被取出并定位为固定在浏览器顶部(或固定到任何预定义框架的顶部)时。然后列会丢失“引导样式设置”(由标题单元格规定),而是应用 ItemStyle-Width。
<asp:TemplateField ItemStyle-Width="80px" HeaderText="Customer ID">
    <ItemTemplate>
        <asp:Label ID="lblCustID" runat="server" Text='<%# Eval("CustomerID")%>'></asp:Label>
    </ItemTemplate>
</asp:TemplateField> 要完美修复此 bug 并不容易。您可能需要逐个微调分离的标题,以确保它与网格完美匹配。如果您不想为此头疼,请按照文章结尾的完整解决方案进行操作。
测试用例 #2: 当页面水平滚动时,分离的标题不会随底层表格/网格一起移动。为什么?因为我们将它们设置为 fixed(position = 'fixed'),所以它们不会移动。

为了解决上述 bug,我提出了一个全新的解决方案。我克隆整个表格并将其放入一个新的图层(div)中。该图层固定在顶部,但在水平滚动页面时会移动。让我们看看下图是如何描述的:

当浏览器实时调整大小时,也会出现同样的问题,那么,底层表格会自动调整大小(即 width='80%')或挤压成最紧凑的形状(如果 width='auto')。在这种情况下,必须重新计算克隆表格的宽度以与底层表格同步。
<script type="text/javascript">
   $(window).bind('resize', function () { 
        //Your code goes here to re-calculate the width of the cloned table to be same with new width value of the underlying table.
   });
</script> 请注意,此解决方案可能会使数据量大的页面运行稍慢,并导致浏览器变得迟钝。您可以在低配置的 PC 客户端上清楚地看到这一点。您可能还会问的另一件事是,为什么我们不创建一个新的空表格,然后复制主表格的整个结构(包括内联样式和外部 CSS)(使用 window.getComputedStyle() 来完成)?它会运行得更快,因为我们没有复制整个数据量大的表格。是的,我也觉得这个提议是对的。但不幸的是,这个提议仍然存在许多未解决的问题。此外,浏览器兼容性仍然是这个提议的一个缺点。 
测试用例 3: 如上所述,克隆整个表格是完美的解决方案。但仍然存在一个小的缺点,如下图所示: 

解决此问题的热修复方法是确保所有“可见”属性(字体、边框、填充...)都已设置,而不是留空“继承”或未按默认值设置。
权衡选项总而言之,有 3 种解决方案可供构建,具体取决于每个问题的复杂性。如果您的网格很简单,或者您不需要支持所有浏览器,请使用第一种解决方案以使您的网页运行得更快。另一方面,如果您不太关心性能而可用性是您最关心的,您可以选择第 3 种解决方案。
| 解决方案 | 如何操作 | 优点 | 缺点 | 
| 1. 分离标题行。 | 逐个分离单元格。将其位置设置为“fixed”。 | 简单易于自定义。 适用于简单的表格设计。 | 并非在所有浏览器中都兼容。 | 
| 2. 克隆标题行。 | 克隆一个具有与标题行相同结构的新 DIV 元素。 | 解决 Safari/Flock 浏览器的 UI 问题。 | 当表格样式过于复杂时,效果不佳。 | 
| 3. 克隆整个表格。 | 将整个表格克隆到一个 DIV 元素(最上层),该元素的高度与整体标题行相同。 | 确保在所有情况下都具有最高的精度和无 bug。除了 IE6 之外,在所有浏览器中都兼容。 | 当表格数据量过大时,将繁重的处理负担留给客户端。 | 
上面的外观和感觉真的很有吸引力,不是吗?我发现它对于那些容易在查看时失去焦点的长数据列表特别有用。特别是第 3 种解决方案是几乎所有浏览器的“万能”方法。 现在让我们构建一个库来支持主要的 UI 功能。如果我们能将所有这些打包到一个与 UI 松耦合的实用函数中,那将是一件好事。在本文中,我实现了 FreezeTableHeader() 函数,并将其放入一个名为“GridHelper”的类中(应该放在一个程序集中)。开发人员的剩余工作是提供参数,如 gridview ID 或 CSS 类,以及进一步的可选变量来控制固定行为。 通过这样做,主要的开发源代码将保持精简。 
现在,让我们直接跳转到现场演示: http://phamdinhtruong.7hostfree.com/FreezingTable.aspx 
您还可以通过动画演示进行抢先预览,该演示展示了在垂直/水平滚动时固定网格标题。此外,网格标题还可以固定在某个容器内。在此演示中,您可以看到嵌套表格的标题固定在其容器内,该容器是父表格的某个行本身。
 
 
结论
上述解决方案帮助我不仅在浏览器窗口内,还在预定义的区域内实现了固定标题行。特别是,完整的解决方案(第 3 种解决方案)现在可以固定甚至“多行”标题部分(其中单元格已合并)。您也可以使用相同的技术来固定页脚行。我真的很想知道这段代码是否能帮助到您。请在评论中告诉我您对本文的看法 。我随时准备帮助您解决任何建议/问题。历史
- 版本 1.0 (2012 年 7 月 20 日) - 初始发布
- 版本 2.0 (2012 年 9 月 10 日) - 修复 Safari 和 Flock 的问题
- 版本 3.0 (2012 年 9 月 25 日) - 修复同一页面上的多个 gridviews 和嵌套 gridviews 的问题。
- 版本 4.0 (2012 年 11 月 7 日) - 修复和微调以精确固定标题行。
- 版本 5.0 (2013 年 1 月 14 日) - 实现完整解决方案,克隆表格并创建一个最上层的图层以适应克隆的标题。


