【问题标题】:How to reduce the amount of DOM redraws while resizing table?如何在调整表格大小时减少 DOM 重绘的数量?
【发布时间】:2015-09-23 10:09:13
【问题描述】:

我有一个具有调整大小功能的表格。实际上,它不是<table> 元素。我使用<div> 元素的集群。 简而言之,我的调整大小函数是一个嵌套的“for”循环。是这样的:

function resizeTable (computedCellWidth) {
    for (var r = 0; r < rows.length; r++) {
        for (var c = 0; c < rows[r].cells.length; c++) {
            rows[r].cells[c].domNode.style.width = computedCellWidth + 'px';
        }
    }
}

据我了解,每个rows[r].cells[c].domNode.style.width = computedCellWidth + 'px'; 都会导致整个文档重绘。因此,如果表足够大,那么调整表大小会极大地降低浏览器的速度。

我尝试使用限制(100 毫秒)来减少调整大小事件的数量,但如果表足够大,那么即使是单次调整大小也会花费太多时间。

我可以先分配所有width 属性,然后再启动单个重绘吗?

【问题讨论】:

  • 在调整大小之前将表格设置为display:none,然后再设置为inlineblock(以相关为准)。
  • @Archer,很好的建议,但是隐藏表格等待进程结束会使表格消失并出现,不是吗?
  • 您是否显示表格数据(即电子表格)?如果是这样,您是否尝试过使用实际的 标签?在这种情况下使用“真实”表是完全可以的。由于给定列的表格单元格宽度都是相同的(colspan 不能承受),我假设浏览器只需要获取然后计算每列的第一个单元格的宽度,然后 only将此值应用于同一列的所有其他单元格。从而减少了计算量和 DOM 读取访问量(浏览器必须获取所有 div 的值,计算 ALL 然后应用值)。
  • @Archer,谢谢!这提高了我的桌子,但只是一段时间。对于大量数据,它仍然运行缓慢。但现在这个数额比以前大得多。
  • @redrum, &lt;table&gt; 不适合我。我的表使用 colspans 和单独的列大小调整,这在 &lt;table&gt; 中工作不正确。这就是为什么我决定使用&lt;div&gt;的集群。

标签: javascript html


【解决方案1】:

以百分比形式给出宽度,尽管像素是为了实现响应式布局。如果由于任何原因不能使用百分比,那么 DocumentFragment 是这种情况下的最佳选择。它用于临时存储 DOM 结构。在修改的片段插入回文档之前,它不会调用浏览器的渲染引擎。

这就是文档的一部分被分割的方式。

var elem = document.getElementById("resizableTable");//assumes resizableTable is the id of the element has to modify
var frag = document.createDocumentFragment(); //method creates an imaginary node object with all properties.
frag.appendChild(elem);

现在遍历片段以进行更改,然后插入回片段。这不会在您每次更改片段中的某些内容时重绘文档。

PS:我知道,我迟到了。但是,认为这可以帮助需要做同样事情的人。

【讨论】:

    【解决方案2】:

    从你分享的代码 sn-p 来看,我怀疑你在避免使用 jquery ......但幸运的是,这是 jquery 的亮点; DOM 操作。

    不知道你的“table”的resize事件是怎么触发的……(鼠标拖动?窗口调整大小?容器改变?);

    如果我是你,我会这样处理。

    1. 用类名标记“表”(最外层的 div),例如.draggable-table。还将“行”标记为.row.tr,将单元格标记为.cell.td
    2. 编写以下事件处理程序:

      function resizeTable(computedCellWidth){
          $('.draggable-table .td').css('width', computedCellWidth+'px');
      }
      

    我没有研究过 jquery 如何实现它的内部结构,但我确信它是一种比嵌套循环快得多的有效方式。

    如果您根本不使用 jquery,那么您真的应该使用,如果您经常处理 DOM。如果您担心它会增加您的项目的大小,请使用 cdn,并且您会从用户第一次访问您的网站时就已经缓存在用户浏览器中的事实中受益。

    【讨论】:

      【解决方案3】:

      再次查看我的答案后,我认为性能不会好得多。我在another answer 上找到了一个可以通过替换类规则来解决性能问题的函数。

      1. 在 html 文档的 &lt;head&gt; 部分添加一个 &lt;style&gt; 标记,其中包含一个类:.dynamic-width {width: /*initial width here*/} 并将该类添加到所有“表格单元格”;
      2. 创建下面的函数(来自@Oriol's answer):

        function setStyle(cssText) {
            var sheet = document.createElement('style');
            sheet.type = 'text/css';
            /* Optional */ window.customSheet = sheet;
           (document.head || document.getElementsByTagName('head')[0]).appendChild(sheet);
           return (setStyle = function(cssText, node) {
                if(!node || node.parentNode !== sheet)
                    return sheet.appendChild(document.createTextNode(cssText));
                node.nodeValue = cssText;
                return node;
           })(cssText);
        };
        

      然后像这样在你的 resize 事件处理程序中调用它:

          function resizeTable(computedCellWidth){
              setStyle('.dynamic-width{ width: '+ computedCellWidth+'px; }');
          }
      

      这预计会更快,因为更改类规则会使一次写入 DOM O(1),而不是更改每个单元格上的规则 O(n)。 如果视觉上应用 css 规则的速度可以忽略不计,则这是正确的。

      【讨论】:

        【解决方案4】:

        我相信您可以使用requestAnimationFrame 批量更新 DOM 并防止布局抖动。我从各种虚拟 DOM 实现中听说过这个想法。

        例如。在你的情况下,这样的事情可能会奏效。

        function resizeTableCell (domNode, computedCellWidth) {
            requestAnimationFrame(function() {
                domNode.style.height = computedCellWidth + 'px';
            });
        }
        

        上面写着here

        【讨论】:

          【解决方案5】:

          有几种方法可以解决。当用户停止调整页面大小超过 150 毫秒时,就会触发一个事件。这样它最后只会触发一次。

          诸如缩放之类的变换动画不会导致重绘,如果您对文本变小没问题,那么成本会更低。您可以缩放整个表格。

          我不知道您的要求是什么,但更好的方法是让 css 自然地处理大小调整,因为它更快。您必须事先使用百分比设置列。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-06-24
            • 1970-01-01
            • 1970-01-01
            • 2011-06-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多