这篇文章上次修改于 1020 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

公司某个项目主要采用 Antd 3 作为 UI 组件库,Antd 确实能解决大多数的业务需求,但在某个页面下出现了表格布局错乱异常,展现出了未对齐的「破碎」效果,如图所示:

Antd-3-Table-Bug.jpg

真是个奇怪的问题 🤔,我看了下,因为右侧固定列的高度是通过 JS 计算出来的。这么做的原因估计是为了避开 position: sticky 兼容性太低的坑,所以才这么做的。

具体的复现代码,可以参考我在 CodeSandbox 上的 案例

一般依赖问题都是升级解决,我也尝试过升级 Antd 到 4,结果发现有很多组件都修改了,此前该项目里的样式覆盖全部失效。升级 React 解决掉「项目依赖」还只是冰山一角,如此多的 CSS 差异在短时间内很难完全排查透彻并进行调整!

那就只能回到项目本身思考了。当时写过一个小 Demo,想了许久都没分析出原因。从表格渲染的数据本身,再到表格内容样式的修改,都没成功复现。我一直在怀疑是不是这个高度的算法问题,然而这个表格并不是 Antd 自己的实现,而是基于 rc-table 这个通用组件库实现,修改源码并不实际。

当时还有其他更重要的事情需要解决,因此这个问题被耽搁许久。


时至今日,我突然想到了一个可能触发此 Bug 的原因,就是 Antd 的模态框出现动画。试了试,确实有了新的发现!所以说有些事情确实不能急,不急的时候真就得来全不费工夫。

复现过程

Antd 3 的模态框默认采用了一个缩放弹出的动画,我把此前的 Demo 修改成「模态框」内显示之后,也并没有出现上述效果。但如果当它变成了异步获取呢...

想要模拟一个异步,最简单的办法就是在 setTimeout 函数里面执行 State 刷新。当我把时间改成 100 毫秒之后,Bug 成功被我复现了!不快不慢,恰好是一个在动画「没播放结束」又「开始了许久」的情况下,和平时调服务器数据的时间差不多。

setTimeout(() => {
  setData(listData);
}, 100);

按照我上面的猜测,强行把 Antd 的缩放动画在开发工具里覆盖掉,再打开模态框,确实没有出现显示异常的情况了。

为什么

CSS3 的缩放动画会让元素变小,元素变小的情况下去计算表格高度,就有可能拿到的是在「动画未结束」播放状态下的高度。再加上异步修改数据会造成表格重绘,改变高度。我猜大概率是因为「异步处理」导致两者恰好踩着点一起执行了。

解决办法

既然已经分析出原因了,那最简单的办法就是用 CSS 把内置的动画直接用 animation: none !important 进行覆盖。但是这样做就会在 300ms 以内的动画预留时长下显示为空,严重影响用户操作体验。

一番搜索之后,Antd 文档里面有一句特别不起眼的问题说明,叫“如何关闭 Modal 动画?”

你可以通过 transitionName=""maskTransitionName="" 去除动画 CSS,但是需要注意的是。该方法为内部方法,我们不保证下个大版本重构时该属性会被保留。

这两个属性名称并没有在文档的其他位置出现,可以看出这并不是蚂蚁那边想让用户修改的东西。但不可否认的是,Antd 3 的源码里面确实有接受这个参数。

那么,这些动画都允许接受什么值呢?我在 Antd 的源码里搜索到了答案。就是在 antd/es/style/core/motion 这个目录里面,存放着各种用于展示的过渡动画。

亲测可以使用的有 fademove-up,这两个动画分别是渐变和平移,都不会改变元素的大小,没有出现本文所述的 Bug 症状。

<Modal transitionName="move-up" title="About Paul" visible={visible}>

Antd 4 的表格已经换成了 sticky,因此使用 Antd 4 的项目都没有这个问题。考虑到现在 Antd 3 不维护了,于是这个问题就不去 Issues 里面凑热闹了。相信能搜到这里来的,都是接盘侠了吧,哈哈哈 😂