xinglie / xinglie.github.io

blog
https://xinglie.github.io
153 stars 22 forks source link

我是如何做固定头部(thead)的 #36

Open xinglie opened 7 years ago

xinglie commented 7 years ago

在前端开发中经常遇到需要页面滚动时,固定某个区域显示,常见表格的需求,因为表格有很多列,如果列名不固定在顶部显示,滚动到底部时,可能就不知道某些列对应的是什么了

那我们就聊一下如何在滚动时固定(thead),让它始终显示在列表的上方

css的方案

如何让tbody滚动

如果我们用css来实现,网上常见的一种方案是给tobdy一个固定高度,然后让它滚动,这样就实现了滚动列表时,thead不动。

有同学说tbody没办法滚动,所以网上也有用div来拼表格的,这样就容易滚动了。其实tbody也可以滚动的,比如tbody{display:block} 这样列的宽度就需要用css来控制了,总之是可以达到的。

这个方案的缺点在于,页面上有很多滚动条,tbody的,页面的。虽然该方案易实施,但在视觉设计师那里通常是不能忍受的。

使用sticky属性

现在css里有一个position:sticky属性,正好可以实现该需求,我们只需要给thead加上position:sticky即可。关于sticky的浏览器支持可以看这里 http://caniuse.com/#search=sticky

这里有一个坑的地方,给thead的position指定sticky,chrome、safari都可以支持,唯独firefox是不行的,也就是写上后没有任何效果 那么对于不支持sticky的,我们只能再想解决方案了

js的方案

这里的js方案还是用css来实施的,只是这个过程中加入了js控制

别人的方案

  1. 上下2个table js加载后,把当前表格分成上下2个table,上table只显示thead,下table只显示tbody。 这个略显麻烦
  2. 再克隆一个thead出来 这个对于原有thead上已经绑定了事件,对于克隆后的也要做处理,也很麻烦。

我希望就用一个thead,尽可能的减少辅助节点,把这个事情搞定

fixed+absolute模拟sticky

我们尝试给thead加上position:fixed,再指定top:0,然后这个thead就脱离的文档流,固定在页面顶部显示了,还好,所有支持fixed的浏览器都表现一致,就连firefox也生效了。

这时候带来的另外问题就是thead脱离文档流后,thead里面的列的宽度就失效了,也就是thead中的列名称和tbody里面的列宽度不一致。

这时候想到的方案就是通过计算tbody中的列宽度,然后同步给thead中的列,这样就能对上了。 但是表格的thead并不是上来就是fixed效果的,而是随着滚动条的滚动,当它处于页面顶部时才进行fixed效果。即thead的position会在static与fixed之间进行切换。

这样子看上去问题就解决了,但是在某些情况下,static与fixed进行切换时,前后的列宽度并不一样,比如static时,某一列是40px的宽度,但是fixed后,通过计算tbody对应列的宽度,它变成38了,虽然切换前后thead中的列与tbody中的列宽度仍然是一致的,但是在切换过程中这种宽度的变化导致表格会有一些让人不舒服的变化,对于我是不能忍的。

既然thead在文档流中和不在文档流中,tbody表现并不一致,那我们干脆直接让thead脱离文档流好了,该如何脱离呢,给它position:absolute,绝对定位,然后不给left top值,这样它还在原来的位置,就是不占高度了,这时候我们仍然计算tbody中的每一列的宽度,给到thead中的列。然后在absolute与fixed之间进行切换时,也不会有任何宽度变化了。

但是,使用absolute或fixed后,原本thead所占的高度就没有了,因为脱离了文档流。这时候整个效果还是不对的,我们要想个办法,找个节点占着原来thead的高度,这样才完美。

我最终找了caption标签,然后把thead的高度给到caption。这样就可以了

ghost commented 6 years ago

可以的 老铁

xinglie commented 6 years ago

源码在这里:https://github.com/thx/magix-gallery/tree/master/tmpl/mx-table

另外对于thead的sticky,现在的浏览器都不支持了 😭

Windseek commented 6 years ago

这个问题我在去年的时候遇到过,当时是这么解决的,我记录到自己的博客园里了,欢迎批评指正http://www.cnblogs.com/windseek/p/6370861.html