使用Javascript设置高度很慢

时间:2017-12-27 15:17:14

标签: javascript jquery css performance reflow

我有两个html表,包含所有类型的元素(span,input,select,...),我想强制这些表的行具有相同的高度。不幸的是,在trtd上设置属性“height”不起作用(如果行包含至少一个超出给定高度的元素,则该行更高)。

我还没有找到一种方法可以用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");
        }
    }

}

4 个答案:

答案 0 :(得分: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()(更慢)。

答案 1 :(得分:1)

如果您不知道细胞的最大高度。您应该将表转换为div并使用display flex

这将允许您拥有所需的行为,但这意味着您将更改HTML代码的构造。

不是拥有第一个表和第二个表的元素,而是必须交替使用另一个,然后是另一个。

答案 2 :(得分:1)

我将通过jfriend00从这个answer中摘录一下。一定要提出他们的答案。

DOM修改

  1. 回流排队。 ....
  2. 请求某些属性可以触发立即重排。您希望避免上述规则的例外情况。例如,如果您请求某些DOM属性需要正确布局以准确报告属性值,并且先前的修改中存在待处理的布局,则浏览器可以在返回您请求的属性之前同步地重新布局文档。这些类型的属性通常涉及屏幕位置和其他属性,这些属性显然会受到文档布局的影响。如果您想了解更多详细信息,有很多关于此主题的文章。在许多情况下,您的代码无论如何都不会使用这些属性,但如果是这样,通常的解决方法是在对DOM进行任何更改之前先请求所有需要的属性。

  3. 立即批量处理所有DOM更改。最糟糕的事情是进行DOM更改,使用计时器等待几毫秒,进行另一个DOM更改,等待一些带有计时器的ms等等,因为你将有DOM更改,重排,重绘,DOM更改,重排,重新绘制等等...相反,请确保在一个同步的Javascript中同时执行所有挂起的DOM更改。然后,这将允许浏览器对重排进行排队并重新绘制,并在完成所有DOM更改后再执行一次。如果您想更好地了解批处理,您将折叠对同一元素的修改,以便仅使用最终值处理一次。因此,如果elementA首先被赋予新值3,然后在同一批次中被赋予值4,则在处理该批数据时,您希望跳过3并仅处理4。

    < / LI>
  4. 有时可以优化DOM修改。 ....

  5. 第2点和第3点非常相关,您将获得每行的offsetHeight,然后设置新值。 所以这些变化不是批量的。每次更改都会导致重排,因为您在下一行的下一次迭代中获得了偏移高度。

    要优化,请读取所有行并保存内存中的所有待处理更改。 然后在新循环中应用新行高。从内存中提取新值的位置。

答案 3 :(得分:0)

不确定原因,但是:

将行高设置为td应该增加td的高度,这将增加tr的高度。 如果没有,你可以设置在div中封装td的内容,然后在其上设置line-height。

另一个加快速度的选择是为所有元素设置相同的样式类。 然后在计算高度后设置类的行高。这将更改使用此类的所有元素的高度。 阅读Javascript的styleSheet对象,了解如何做到这一点......