解決方案(一)— Ant-design Table組件當滾動列的行高變化時,固定列的行高不會同步變化,或固定列變化滾動列不變,造成佈局破壞。


問題

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》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章