使用flex和div布局实现表格的解决方法(类似天眼查那种)
使用flex和div布局实现表格的解决方法(类似天眼查那种)
因为业务需求,几个地方用到类似天眼查工商信息那种表格.
最初我是用table写的,然后我发现很麻烦,假设像天眼查一样有几十个字段,那么表格的tsx就要写一大坨.再加上表单,工作量可以说是非常大了.而且没有可复用性.
其他地方本来也要用到类似的表格,
(但是最后我发现还是用table方便,虽然没有复用性,但是至少改起来很容易.进行封装以后你会发现改起来很麻烦,需求稍微变动一点,你这边搞起来都很麻烦.还有一些不好处理的bug,反正你这个组件目前只有固定几个地方会用到.复制粘贴也是很快的)
第二版我就改成用flex布局实现了.
使用了antd的栅格组件Row和Col.本质上是flex布局的效果.
采用类似配置表单的方式,直接遍历列表,把对应的格子渲染出来,
然后Row设置flex-wrap,这样内容超出的时候就会换行.我们可以控制每个格子的span值,控制表格每行的显示
表格的每一个条目都是像表单一样包含label和content,
然后表格的边框,可以先设置Row的左边框和上边框,然后设置每个格子的右边框和下边框,这样的效果就是类似表格的边框
使用col的span属性划分
第一个问题
很快就碰到第一个问题,就是表格的合并单元格,这个本来我是用span划分空间的,但是碰到不是整数的情况,就会发现表格的格子对不齐
解决方案就是用Col组件的flex属性,每个格子设置成固定flex值.
第二个问题 缩放时发生换行
缩放时发生换行,导致最后一个格子换行到第二行,表格发生变形
也就是浏览器的ctrl+滚轮的缩放功能,这个bug过了好几个月才被发现.因为一般人不会缩小网页,一般是放大网页,放大的时候表格没有异常.
其实应该不是很影响使用,因为缩放到70%的时候才发生换行.
第一个解决方案,增大Row的宽度
很容易想到,只要我们增大Row的宽度,那么就不会换行了,
这个方案主要的影响是,border-top会有一点点超出表格边界的部分.
这个多余的border其实也有办法消除,拿一个别的元素遮一下就行了.
我觉得这样不太好.很蠢
第二个解决方案,单独设置每个单元格的border
我们去掉Row的border设置,然后我们传入每个格子信息的时候,顺便设置每个格子的border
因为Row和Col组件默认是border-box盒模型的,也就是border也计算在width里,
所以我们单独设置border并不会撑大表格.
这个也很蠢,写那么多样式代码,不如不封装
第三个解决方案 conten-box
终于我发现问题的根本所在,因为Row是border-box盒模型,所以给它设置border会挤压内部的格子的空间
所以我们flex设置的值不正确,我们以为每一行格子的宽度是1200px,实际上,由于设置Row的border,每一行格子拥有的宽度是1199px
所以我们把Row的盒模型,设置为
box-sizing:content-box
这样只改了一行代码,问题就解决了.
宽度自适应的问题
其实一开始没有找到自适应的方法,所以我才改成设置表格固定宽度的方案
不过现在我已经知道如何正确设置了。
flex布局里空间的分配
虽然一直都用flex布局,但是其实一直没有完全理解。
基本上都是flex:1
flex:宽度
和flex:auto
这几个值在用。
也就是说,用的基本上只用到一个属性,另外两个flex-grow和flex-shrink都是自动推算的,从来没主动设定过,而且完全没感觉到需要用这两个属性的地方。
确实完全不影响使用。
flex-shrink 属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
flex 属性属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
其实flex:1 实际上是 flex: 1 1 0%;
lex:auto
= flex: 1 1 auto;
这两个平时区别不大,只是flex:1
flex-basis为0% 这种方式会覆盖原来的width
所以平时还是auto会好一点。
但是我因此误解了,以为 flex:1
和flex:8
这样也能工作,实际是不能工作的。
flex整数的情况下只支持0和1.
其他情况需要设置宽度,
所以我们用百分比可以正常分配
formLayout: {
labelCol: { flex: 'calc(100% / 9)' },
wrapperCol: { flex: 'calc(100% - 100%/9)' },
},
这样表格分配空间就不像用Col组件,只能用span,在24以内的整数里面分配
span的情况, 样式会变成 ant-col-2.6666666666666665,antd还是不支持这种的。
这种情况用flex属性会更灵活。
思考
在table里面实现这个边框还是很简单的,
th,td都设置边框,但是还有一个border-collapse属性,使得表格边框之间不发生重叠.
但是拿div实现表格边框就很麻烦,flex布局下没有方便的css属性.