2017-12-27 273 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