解决方案(一)— Ant-design Table组件当滚动列的行高变化时,固定列的行高不会同步变化,或固定列变化滚动列不变,造成布局破坏。
Ant-design Table组件当滚动列的行高变化时,固定列的行高不会同步变化,或固定列变化滚动列不变,造成布局破坏。本来以为是文档没有看仔细,想寻求官方的配置方式来解决该问题。既然官方仍在`处理中`,在这里给出自己的解决方案,希望能够帮到其他同学。根据`产生原因`可分为两类- 滚动列发生变化,固定列不变,布局被破坏。- 固定列发生变化,滚动列和另一个固定列不变,布局被破坏。在组件更新(com
问题
Version: Ant Design 3.26.7
Issue:Ant-design Table组件当滚动列的行高变化时,固定列的行高不会同步变化,或固定列变化滚动列不变,造成布局破坏。
本来以为是文档没有看仔细,想寻求官方的配置方式来解决该问题。既然官方仍在处理中
,在这里给出自己的解决方案,希望能够帮到其他同学。
原理
首先,先解释下 Table组件“固定头和列” 的实现原理。我们所看到的一个Table组件,其本质是有三个Table元素组成,只不过被用特殊样式的容器div(Wrapper div)包裹起来。如下所示
<div class="ant-table-content">
<div class="ant-table-scroll">...</div>
<div class="ant-table-fixed-left">...</div>
<div class="ant-table-fixed-right">...</div>
</div>
通过类名我们可以很直观的了解,一个表被固定在左,一个固定在右,一个位于中间用于滚动。
在创建表的时候,我们通过Column
的fixed: true|left|right|false
属性来决定该列属于哪个容器,或者说 “指定这三个容器各自包含哪些列”。准确来说,应该是 指定left,right这两个固定容器各自包含哪些列,因为scroll容器包含了全部的列 ,这也是实现这种推拉效果的核心。
需要注意的是,ant-table-fixed-left
与ant-table-fixed-right
,由于被固定在左右,所以不能左右滚动,所以它们的包装容器,被设置为
<div style=“max-height: ${y}; overflow-y: scroll;”> </div>
仅实现上下滚动。
而ant-table-scroll
需要同时满足左右上下滚动,所以被设置为
<div style=“max-height: ${y}; overflow: scroll;”> </div>
其中这里的y
,等于你所设置的Table组件的scroll.y
属性。(个人见解,如果有误请指出,先谢过)
分类
先看正常状态
根据产生原因
可分为两类
- 滚动列发生变化,固定列不变,布局被破坏。
- 固定列发生变化,滚动列和另一个固定列不变,布局被破坏。
这里我们以“右固定列发生变化”
为例,进行问题解决,通过同样的方式你也可以很容易得出其他情况的解决方式。
实例
先给出表的代码
<Table id={tableId} rowKey={(t, index) => {
/**指定key,为了在行tr高改变的时候,获取其他容器中对应的行*/
t.key = `${t.name}-${index}`; return t.key;
}}
components={components}
rowClassName={() => 'editable-row'}
defaultExpandAllRows
scroll={{ y: 'max-content', x: 1300 }}
pagination={false} columns={columns} dataSource={dataSource} />
题
右固定列
发生变化,采用滚动列和左固定列伸缩
恢复布局。
解
在组件更新(componentDidUpdate)时,获取右固定容器发生变化的行tr
的真实高度(height),对滚动容器和左固定容器的对应行tr
的 style.height 进行相应改变。
const [rowKeyObject, setRowKeyObject] = useState({});
const onUp = (rowKey) => setRowKeyObject({ rowKey });
const didUpdateRef = useRef(false);
useEffect(() => {
if (!didUpdateRef.current) {
didUpdateRef.current = true;
return;
}
const { rowKey } = rowKeyObject
if (!rowKey)
return;
const scrollDiv = document.querySelector(`#${tableId} .ant-table-scroll > .ant-table-body`);
const leftFixedDiv = document.querySelector(`#${tableId} .ant-table-fixed-left .ant-table-body-inner`);
const rightFixedDiv = document.querySelector(`#${tableId} .ant-table-fixed-right .ant-table-body-inner`);
const cssSelector = `table.ant-table-fixed tr[data-row-key='${rowKey}']`;
const rightFixedTr = rightFixedDiv.querySelector(cssSelector);
const leftFixedTr = leftFixedDiv.querySelector(cssSelector);
const scrollTr = scrollDiv.querySelector(cssSelector);
const theoryTrHeight = getComputedStyle(rightFixedTr).height;
scrollTr.style.height = theoryTrHeight;
leftFixedTr.style.height = theoryTrHeight;
console.log(theoryTrHeight);
});
注意
useEffect()
在组件挂载(componentDidMount)和更新(componentDidUpdate)时都会被执行,显然在挂载时我们不需要执行函数中的复杂逻辑,这里使用易变对象ref
(mutable ref)来优化,ref.current
做状态标记,挂载时不再执行复杂逻辑。- 这里
id={tableId}
,是针对多表同时存在时使用的,tableId
作唯一标识,如果你的Document中只有一个Table组件存在,那么你可以忽略该属性。 - 为了获取变化的行tr,我们需要指定Table组件的rowKey属性(rowKey对应了tr的
data-row-key
属性),同时需要在tr高度发生变化时将rowKey值传递给useEffect()
,所以你需要保证你的EditableCell组件
能够准确的拿到相应rowKey
值。在这里,我将它绑定到了record.key
。 - 设置rowKey状态时,没有直接使用
而是使用const [rowKey, setRowKey] = useState(null);
原因是——如果某行tr高度持续变化,那么传递到const [rowKeyObject, setRowKeyObject] = useState(null);
setRowKey(rowKey)
的rowKey
将是相等(===
)的值,React认为State未发生变化,组件不会更新,useEffect()
不会被执行。而setRowKeyObject({rowKey})
,每次会创建一个新的State对象,其引用Reference,是不相等的(===
),组件会更新,useEffect()
会执行。 - 行tr高度但凡发生变化,你都需要促使组件更新,
useEffect()
执行。那么你需要在EditableCell组件
中设置相应的监听函数,例如onKeyUp
、onMouseUp
、onMouseOver
、onMouseEnter
等等。例如,return (<td {...restProps} onKeyUp={() => onUp(record.key)} onMouseUp={() => onUp(record.key)} > {editable ? this.renderCell() : children} </td>);
如果有错误的地方,请指出,先行谢过。
修订:Ant Design v4已经发布,直接升级到v4,问题就全解决了
,《从 v3 到 v4》
更多推荐
所有评论(0)