浅谈表格组件的实现:固定表头和固定

2019-07-05 14:03 来源:未知

  在前端开发中,表格组件相对来讲是比较复杂的组件之一,主要原因在于大家对表格组件的需求不同,笔者没看到过一个表格组件可以覆盖所有人的需求。

  Bootstrap 类:CSS 就可实现的表格,主要用在信息展现类的页面上。

  中后台类:着重在展现,编辑通过按钮来操作,主要用在中后台系统中。与 Bootstrap 类表格比较大的一个分界点就是有固定表格头、固定列等功能。

  Excel 类:着重在编辑上,主要在线数据编辑的场景,这类场景相对来讲比较小众。这类表格组件对性能要求较高,和前面两种相比,有一些独有的特性:比如双击行内编辑、固定行等功能。

  对于适用于 Bootstrap 类表格的需求,建议直接使用 Bootstrap 提供的方式来使用。对于中后台类的表格组件,比较常见的有这么几个需求:

  这些特性里面最有趣的应该属于固定表格头、固定列的实现,本篇文章主要用来讲述这两种特性的不同实现方式,以及应该选取哪种实现方式。

  本篇文章的内容和示例没有使用任何框架,只要你可以熟练的使用 HTML、CSS、jQuery,理论上都能读懂。

  为了降低各位的阅读门槛,两个特性的实现都准备了在线示例。每个在线示例都是通过对一个最简单的 Bootstrap 3.0 的表格进行修改来完成的,这个示例可以在这里查看。

  如果表格中的数据是有滚动条的,那么用户在滚动的时候会希望表格头是固定在上方,否则没办法看出单元格数据对应的含义。

  最简单的思路是使用两个 table,一个用来显示表格头,一个用来显示表格内容。使用另外一个元素来包裹表格内容的 table,设置一个 overflow: auto 来展现滚动条。实现方式如下图所示:

  这个版本有一个非常明显的问题,就是表格头和表格内容的列宽不一致,会出现错位的情况。错位的原因如下:表格内容需要显示一个滚动条、表格头不需要显示一个滚动条,这样两者的宽度就产生了一个宽度差。一般的做法是在表格头上增加一个额外的元素去弥补这个宽度差,这个元素一般叫做 Gutter。

  除了 Gutter 以外,还有一些其他的情况需要说明,所以加了四个箭头,下面分别做一些说明。

  Gutter 的定义参考上文中的说明,Gutter 在箭头 1 位置,实现方法请参考示例 HTML 中的 th.gutter 元素,以及 CSS 中的 th.gutter 的样式定义。在实际的场景中,这个 Gutter 的宽度会因为浏览器和操作系统产生变化,需要动态计算这个宽度。实现代码如下:

  右侧边框参考箭头 2 的位置,因为 Gutter 的存在,表格内容的实际宽度就少了这个滚动条的宽度,表格右侧的边框也就无法正常显示。在这个例子里面,使用了伪元素 before 为最外层的元素添加了一个右侧边框。实现代码如下:

  table 上,table的父元素增加了滚动条之后,会导致因为 table 的底部的边框并不能显示出来。所以需要在最外层的元素上加上一个底部边框,用来弥补这个边框的缺失。在这个例子里面,使用了伪元素 before 为最外层的元素添加了一个右侧边框。实现代码如下:

  因为表格头和表格内容现在变成了两个独立的 table 元素,两者的列宽度同步变成了一个问题。在这个例子里,恰好可以通过设置 table-layout 属性为 fixed 来解决,实现代码如下:

  关于 table-layout 的说明,可以参考 这篇文章 。简单来讲,table-layout 的两个值的工作原理如下:

  仅仅通过设置 table-layout 为 fixed 是无法解决问题的,修改下的样式就可以继续产生错位的情况,可以参考这个例子。在这个例子里面,只为表格内容中的第一行的第一个 td 加了一个 width 属性,表格头和表格内容就产生了错位。

  固定表格头是通过把表格头和表格内容分成两个 table 来实现,固定列的实现本质上是把固定列所需要的表格头和表格内容克隆一份来实现。实现原理如下图所示,固定列用的表头和表格体使用深色来表示:

  固定列的实现依赖于固定表头的实现,所以是由固定表头的例子修改而来,可以在线查看。例子效果如下图所示:

  因为固定列和表格主体的滚动条是独立的,所以在表格主体滚动的时候,需要同步到固定列的表格内容的滚动条上。使用 jQuery 实现的代码如下:

  同步 hover 效果的会麻烦一些,因为除了表格主体进行 hover 会影响固定列之外,固定列的 hover 也会影响到表格主体。因为 Bootstrap 的 hover 效果使用了 :hover 来实现,所以需要增加一个使用 hover 的 class:

  表格的每行的行高是统一的:因为这个例子中的固定列的表格内容只渲染了一列,所以固定列的行的高度是受那一列控制。但是表格主体中的行高是受所有行的控制,无法通过 CSS 来实现两个无任何关联的元素的高度同步。

  固定列的列有固定宽度:因为表格主体的列宽是由表格的宽度决定的,固定列只渲染了一列,同样无法通过 CSS 来同步表格主体对应的列宽。

  动态同步左右两边的行高和列宽:优点是性能较好,只会渲染出需要渲染的列。缺点是同步行高、列宽的时机比较难以掌控,会有一些边缘案例导致有 Bug 出现,比如出现列宽、行高不一致导致的错位。

  覆盖在表格主体上的固定列渲染所有的列:优点是不需要动态同步行高和列宽,让浏览器自己去控制行高和列宽,很难出现错位的 Bug。 缺点也很明显,就是在数据量较大或者表格内渲染内容较为复杂的场景下,会导致渲染次数过多,产生一定的性能问题。

  BTW,表格组件不一定需要突破这两个限制,有时候加上这两个限制是必须的,这个需要看实际的业务场景。对于 Excel 类表格组件来讲,固定的行高是保证组件性能的基础,加上这个限制也让一些其他特性的实现难度降低。

  对于前端程序员来讲,实现复杂组件一直是小众工作。一方面是由于实现难度大,另一方面是因为投入产出比过低,不如直接使用开源产品或者商业产品。

  如果你有意去自己实现一个表格组件,希望这篇文章能对你有所帮助。返回搜狐,查看更多

TAG标签: 表格的题头
版权声明:转载须经版权人书面授权并注明来源