2017-12-27 274 views
1

我有兩個包含各種元素(span,input,select,...)的html表格,我想強制這些表格的行具有相同的高度。不幸的是,在trtd上設置屬性「高度」不起作用(如果該行包含至少一個超過給定高度的元素,則該行更高)。使用Javascript設置高度很慢

我還沒有找到一種方法,我可以用css強制行高,所以我寫了一個循環遍歷所有行的Javascript函數,檢查左表的高度與相應行的高度在右表中,如果它們不同,我將高度(改變樣式)設置爲最大值。

它的工作原理......但如果表格有很多行,則速度非常慢!我認爲這是由於這種風格的每次改變都會導致迴流。

任何提示?請注意,我無法合併這兩個表。

這裏我的代碼剪斷,但也許我總共需要不同的方法......

var rightTableRows = mainTable.children("tbody").children("tr:parent"); 
var leftTableRows = colHeader.children("tbody").children("tr:parent"); 

for (chr=0;chr < leftTableRows .length;chr++) { 
    var rowLeft = leftTableRows [chr]; 
    var heightleft = rowLeft.offsetHeight; 
    var rowRight = rightTableRows[chr]; 
    var heightright = rowRight.offsetHeight; 
    if(heightleft != heightright){ 
      console.log("left: "+heightleft +" - right: "+heightright); 
     if(heightleft>heightright){ 
      rowRight.setAttribute("style","height:"+heightleft+"px"); 
     }else{ 
      rowLeft.setAttribute("style","height:"+heightright+"px"); 
     } 
    } 

} 

回答

2

您正在反覆閱讀,然後寫入DOM。這被認爲是表現的一大禁忌。正確的做法是先完成所有的「讀取」,然後再進行所有的「寫入」 - 否則就會在中間強制進行迴流/計算。你會實際上是有兩個迴路,一個找到正確的高度,然後第二應用於他們更好:

var rightTableRows = mainTable.children("tbody").children("tr:parent"); 
var leftTableRows = colHeader.children("tbody").children("tr:parent"); 
var length = leftTableRows.length; 
var heights = []; 

for (var chr = 0; chr < length; chr++) { 
    var rowLeft = leftTableRows[chr]; 
    var heightleft = rowLeft.offsetHeight; 
    var rowRight = rightTableRows[chr]; 
    var heightright = rowRight.offsetHeight; 

    if (heightleft > heightright) { 
     heights.push({ 
      elem: rowRight, 
      height: heightleft 
     }); 
    } else { 
     heights.push({ 
      elem: rowLeft, 
      height: heightright 
     }); 
    } 
} 

for (var i = 0; i < heights.length; i++) { 
    heights[i].elem.style.height = heights[i].height + 'px'; 
} 

現在元素及其新的高度得到存儲在一個數組對象,那麼你只遍歷數組。第一次循環後,您再也不會從DOM讀取數據。其他優化包括刪除不需要的if()語句,緩存HTML節點列表的長度,特別是編寫style.height而不是setAttribute()(較慢)。

+0

酷,thx。我馬上嘗試。在我看來,如果應該提高性能:我只有在不同時才設定高度。 – Zardo

+0

性能更好! :-)它不工作在IE瀏覽器,我檢查它,我會回來這裏... – Zardo

+0

很酷,讓我知道如果有任何錯誤報告在IE瀏覽器(和哪個版本),我們可以嘗試通過他們 – skyline3000

0

不知道關於這個的原因,但:

設置的line-height風格TD應該增加td的高度會增加tr的高度。 如果不是,你可以設置在一個div中封裝td的內容,然後在其上設置行高。

另一種方法是加速所有元素的設置。 然後在計算完高度後,設定班級的行高。這將改變所有使用這個類的元素的高度。 閱讀關於Javascript的styleSheet對象,瞭解如何完成此操作....

1

如果您不知道單元的最大高度。你可能應該把你的表格變成div,並使用display flex

這將允許你有你想要的行爲,但會暗示你改變了HTML代碼的結構。

而不是有第一個表和第二個的元素,你將不得不交替一個然後另一個。

+0

我已考慮到這一點。這是一項艱鉅的任務,但我認爲在未來的將來我必須這樣做。目前我需要一個快速(臨時)解決方案;-) – Zardo

1

我要從jfriend00上摘錄這answer。肯定會upvote他們的答案。

DOM修改

  1. 迴流進行排隊。 ....
  2. 請求某些屬性可以觸發立即重排。上面的規則也有例外,您要確保避免。例如,如果您請求某些DOM屬性需要正確報告屬性值的正確佈局,並且存在來自先前修改的未決佈局,則瀏覽器可以在返回您請求的屬性之前同步中繼該文檔。這些類型的屬性通常涉及屏幕位置和其他屬性,這些屬性顯然會受到文檔佈局的影響。如果你想找到更多的細節,這個話題有很多文章。在許多情況下,您的代碼無論如何都不會使用這些屬性,但如果是這樣,通常的解決方法是在對DOM進行任何更改之前先請求所有需要的屬性。

  3. 一次批量修改所有DOM更改。最糟糕的是做一個DOM改變,用計時器等幾秒,做另一個DOM改變,用計時器等幾秒,等等,因爲你會有DOM改變,迴流,重畫,DOM改變,重新焊接,重新繪製等等。相反,請確保您在同一塊Javascript中同時執行所有待處理的DOM更改。然後,這將允許瀏覽器排隊重排和重繪,並在完成所有DOM更改後再執行一次。如果你想更好地瞭解批處理,你可以將修改合併到同一個元素中,以便只處理一次最終值。因此,如果元素A第一次被賦予3的新值,然後在同一批處理中被賦予值4,那麼在處理該批數據時,您要跳過3並且僅處理該元素4。 DOM修改有時可以優化。 ....


點2和3是非常相關的,你得到的offsetHeight的每一行,然後設置一個新值。 所以這些更改沒有批處理。每次更改都會導致迴流,因爲您在下一行的下一次迭代中獲得偏移高度。

要進行優化,請讀取所有行並將所有掛起的更改保存在內存中。 然後在新的循環中應用新的行高。從存儲器中提取新值的位置。

+0

哦。涼。隨着你的建議,總時間從40秒減少到400毫秒(加速100倍!) – Zardo