问题

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>

通过类名我们可以很直观的了解,一个表被固定在左,一个固定在右,一个位于中间用于滚动。

在创建表的时候,我们通过Columnfixed: true|left|right|false 属性来决定该列属于哪个容器,或者说 “指定这三个容器各自包含哪些列”。准确来说,应该是 指定left,right这两个固定容器各自包含哪些列,因为scroll容器包含了全部的列 ,这也是实现这种推拉效果的核心。

需要注意的是,ant-table-fixed-leftant-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),对滚动容器和左固定容器的对应行trstyle.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);
    
    而是使用
     const [rowKeyObject, setRowKeyObject] = useState(null);
    
    原因是——如果某行tr高度持续变化,那么传递到setRowKey(rowKey)rowKey将是相等(===)的值,React认为State未发生变化,组件不会更新,useEffect()不会被执行。而setRowKeyObject({rowKey}),每次会创建一个新的State对象,其引用Reference,是不相等的(===),组件会更新,useEffect()会执行。
  • 行tr高度但凡发生变化,你都需要促使组件更新,useEffect()执行。那么你需要在EditableCell组件中设置相应的监听函数,例如onKeyUponMouseUponMouseOveronMouseEnter等等。例如,
    return (<td {...restProps} onKeyUp={() => onUp(record.key)} onMouseUp={() => onUp(record.key)} >
                {editable ? this.renderCell() : children}
            </td>);
    

如果有错误的地方,请指出,先行谢过。

修订:Ant Design v4已经发布,直接升级到v4,问题就全解决了《从 v3 到 v4》

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐