背景
我参与的 React 项目中,对于表格组件,有大数据量展示需求(不分页)。经过多方比对,最终选用了 Audodesk 公司的开源项目 BaseTable。
不仅如此,在项目中还使用了 BaseTable 的 Auto Resize 特性,因为表格展示在 Flex 布局容器中,需要表格组件有自动适应容器尺寸变化的能力。
但是在项目测试过程中发现,在某些情况下(例如:调整浏览器缩放比例、调整浏览器尺寸) BaseTable 所在的 Flex 容器会出现滚动条(注:容器上设置有 overflow: auto)
例如:
发现
经过仔细研究,通过 F12 查看发现:Flex 容器出滚动条的那些情况,其内部表格的尺寸要比容器尺寸大,但并没有大很多,只是大了不到 1px。
然后我去看了BaseTable 的 AutoResizer 的实现,发现:AutoResizer 组件动态计算的 width 和 height 是通过获取其父元素的 offsetWidth、offsetHeight 得到的。
难道是坑在了 offsetWidth、offsetHeight 上?
验证
写了个极简的例子验证了一下:
- 容器
outer:宽度300.6px,高度200.6px,overflowauto(目的是验证四舍五入与滚动条问题) - 点击按钮,将读取容器
outer的offsetWidth、offsetHeight值,作为子组件inner的width和height - 此时
outer没有出现滚动条 - 缩放浏览器,会发现
outer出现滚动条。 - 且即便回到 100% 的缩放比例,
outer滚动条也不会消失
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<button onclick="fn()">fn</button>
<div id="outer" style="width: 300.6px; height: 200.6px;
background-color: orange; overflow: auto;">
<div id="inner" style="background-color: rgba(0, 255, 0, 0.2)">
</div>
</div>
<script type="text/javascript">
function fn() {
const outer = document.getElementById("outer");
const inner = document.getElementById("inner");
inner.style.width = outer.offsetWidth + "px";
inner.style.height = outer.offsetHeight + "px";
}
</script>
</body>
</html>
官方解释
offsetWidth、offsetHeight确实会进行四舍五入- 想要得到带小数的原始值,应该使用
getBoundingClientRect()获取
解决方案
- 修改开源组件,将
offsetWidth、offsetHeight修改为getBoundingClientRect().width、getBoundingClientRect().height,并用 Math.floor 向下取整