xinglie / xinglie.github.io

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

使用div模拟table #40

Open xinglie opened 5 years ago

xinglie commented 5 years ago

本项目仅供参考,需要浏览器css支持display:flex,position:sticky等特性

为什么模拟table

从功能上来讲,行列的数据更适合使用table,所以当您的需求中没有固定表头,固定列时,请直接使用table,模拟table更多的是解决固定表头,固定列等事情。

table有哪些问题

body不能滚动

当数据量多时,我们期望表头或表尾固定,只滚动中间区域,但是<tbody>不能做为滚动容器。如果我们强制改变<tbody>display使它可以滚动,然后<thead>中的列和<tbody>中的列就对不齐了。

然后我们可能就要上javascript然后各种同步列的宽度了,然后你会发现解决1个问题会引入3个问题,到最后列可能还会有些许的偏差并没有对齐。

这个网上的案例有一些,感兴趣的话可以搜搜看

sticky

我们知道css3position新增了sticky,如果浏览器支持,直接在<thead>上使用position:sticky就完成了表头固定,多好?

chrome曾经支持过<thead>上设置position:sticky,但是后来不知为何又去掉了,然后目前没有浏览器支持<thead>上设置position:sticky,这都什么鬼?具体可以看下caniusehttps://caniuse.com/#search=sticky

table做固定表头,固定列功能

网上常见的做法是使用4个表格来完成相应的功能,以ant.design为代表,可以看下它的效果和实现:https://ant.design/components/table-cn/

这种做法实现起来麻烦,计算的量也不少,在表头固定、首列固定、尾列固定、表尾固定这些需求同时存在的情况下,列对齐需要计算,然后同步。行高需要计算,然后同步,据说ant.design是以中间行为最大高度,然后去同步首列中的行和尾列的行。

做到最后依然可能对不齐,我在ant.design中的表格组件上经常能见到对不齐的bug

做完各种计算后,如果要实现鼠标移上行变色,你会发现css中的hover伪类没法使用,因为表格是分离的,这时候就又需要绑定javascript事件进行模拟实现,这个简直了...

div模拟表格

该方法仍然需要计算,但计算量少了很多,只需要列宽计算

因为行没有被拆分,所以行高不需要计算对齐,同时可以使用css中的hover伪类实现鼠标移入变色

demo地址 https://xinglie.github.io/magix-table/index.html 项目地址 https://github.com/xinglie/magix-table

行高

由单元格内容自动撑开,最好不要在单元格上写高度,可以在单元格内再套一个div之类的来处理高度。因为整行的单元格并没有分离,所以行高不需要计算,同时可以使用csshover伪类来处理鼠标移上的背景色。

列宽

列宽需要javascript计算,其实也谈不上计算,因为计算宽度的过程可以省去,比如你给每一列都写好了宽度,或使用百分比则不需要计算。

列宽的处理上更重要的是把表格head中的列宽同步给body中的列,列宽没办法自动处理,这一步还是需要javascript来进行同步。

同时考虑到类似table实际运用,宽度可能是百分比,可能是定值,也可能混用,也可能省略等,以方便为目的,对head中的列宽进行计算后再同步给body中的列

单元格合并

列合并不是问题,因为所有的单元格都在一行上,无非是计算的时候,把合并列的单元格的宽度自成它合并几列的宽度即可

行合并是个大问题,目前并未找到合适的方案,示例中的head中的行合并其实是视觉上的效果,并不是真正意义上的合并。也仅head中的单元格做了视觉上的合并,body中的并没有做,因为该“行合并”方案本质上有很大缺陷,就没再深入去处理。

后续

未来可能使用css中的display:grid来模拟表格,这个方案在合并单元格上有着天然的优势,也许可以用它做出更好的表格

当然,还是希望position:sticky能尽早的用在table上,目前虽然像chrome支持在th上使用position:sticky,但是也仅是th上,而且还有bug,期望浏览器赶快完善起来吧。