js table 實現列首固定+列表竪向滾動

350 阅读3分钟

問題:表身竪向滾動后,列寬無法與表頭保持一致

最近有個工作,要求把vue架構下的一個表格變成列首固定,列表内容竪向滾動。

上手把tbody設置display:block;overflow-y:auto了以後發現問題。

表格本來是列寬自適應,tbody加了滾軸以後thaed和tbody的列寬變各自自適應了,列寬不一致。

爲了解決這個問題上網查了一圈,主要有以下幾種建議:

1.全部設置固定列寬Or百分比列寬

我這個表格本身根據檢索内容每次顯示的列數和内容都不一樣,而且數據長度也不一樣,固定列寬不太好實踐,否決

2.在表頭和表身使用width:100%

不太理解這個意圖,但是我的表格橫向特別寬,早就超過了瀏覽器寬度,所以這個方法也不行

3.表頭和表身設置同樣的id

以前用react時遇上類似的問題,當時確實在coldef裏設置同樣的id會使得列寬自動聯動,但是試了一下在vue這裏不行

4.表頭表身分成兩個table來操作

挺多回答都提到了這一點,沒搞懂爲什麽,試了一下沒有啥用

5.做兩個表頭,一個跟著表身滾動,一個留著顯示

這。。。大可不必

解決方法:手動將表頭列寬賦予表身

最後還是決定采用最原始的辦法,那就是直接取表身列寬賦予表頭。

參考了這個帖子13樓的建議

     adjustHeaderWidth: function(){
        var thElements = document.getElementsByTagName("tr")[0].children;
        var tdElements = document.getElementsByTagName("td");
        if(tdElements){
            for (var i = 0; i < thElements.length; i++){
                thElements[i].style.width = tdElements[i].offsetWidth + "px";
            }
        }
    },

我的表頭有複數行,所以是檢索的tr取第一行。如果有跨複數列的表頭,處理起來就比較麻煩了。

做了個執行按鈕試了一下,可行。

執行時機:利用MutationObserver監聽表格發生變化的瞬間

問題是這個方法應該在何時執行。

我的表格是這樣的,有個檢索filter,改變内容時會重新加載表頭和表身,因爲根據filter不同列的數量和内容也不同。 這個加載的過程不涉及頁面重新加載,所以DOMContentLoaded之類的用不了。 嘗試把onload賦給tr,table之類的標簽,也沒有反應。

這時候就很懷念react。也是因爲我第一次接觸vue,所以不是很瞭解每個元素的生命周期。

後來找到一個解決方案,就是MutationObserver。可以監聽dom的變化,包括children的變化,然後觸發回調方法。

於是我在表格觸發去server取data并且獲取data成功的時機,使用了MutationObserver去監聽表格的變化。

因爲表格的表頭一直都會顯示,但是表身在顯示之前dom是不存在的,所以我只能去監聽父級的table。

            var observer = new MutationObserver(this.adjustHeaderWidth); // 將上述調整列寬的方法作爲回調
            observer.observe(document.getElementById(監聽table的id), {
                childList: true, // 監聽children的變化
                subtree: true, // 也監聽children的children的變化
                characterDataOldValue: true
            });

沒想到這就成了。表格内容顯示出來的瞬間列寬就已經是調整好的狀態。 在網上查了一圈沒有特別完整的解決建議,發出來希望能給大家一點參考。