【问题标题】:High performance selectable cells in large table - IE6大型表格中的高性能可选单元格 - IE6
【发布时间】:2017-05-15 05:17:16
【问题描述】:

我正在开发一个具有严格业务要求的应用程序,以显示最多 60 行和最多 50 列的 html 表格。

理想情况下,用户可以选择单个表格单元格,或者单击并拖动以选择多个单元格。

我的问题是我目前仅限于使用 IE6,而且我一直很难找到(或编码)一种方法来允许在这么多单元格上进行这种选择而不会严重降低性能。

我目前的方法基本上是这样的:

$(document).ready(function() {
    var selecting = false;
    var colStart, rowStart;

    var tableContainer = $("#tableContainer")

    tableContainer.delegate("td", "mousedown", function() {
        //Clear Selection
        tableContainer.find("td.selected").removeClass("selected");

        $(this).addClass("selected");
        colStart = $(this).index();
        rowStart = $(this).parents("tr").index();
        selecting = true;
    }).delegate("td", "mouseover", function() {
        if (selecting) {
            //Clear Selection
            tableContainer.find("td.selected").removeClass("selected");

            var theCell = $(this);

            // Get the row and column numbers of the current cell 
            var colEnd = theCell.index();
            var rowEnd = theCell.parents("tr").index();

            // Account for rowEnd being smaller than rowStart
            var rowSliceStart = Math.min(rowStart, rowEnd);
            var rowSliceEnd = Math.max(rowStart, rowEnd);

            tableContainer.find("tr").slice(rowSliceStart, rowSliceEnd + 1).each(function() {
                var colSliceStart = Math.min(colStart, colEnd);
                var colSliceEnd = Math.max(colStart, colEnd);

                // Add the required class to the children
                $(this).children().slice(colSliceStart, colSliceEnd + 1).addClass("selected");
            });
        }
    }).delegate("td", "mouseup", function() {
        selecting = false;
    });
});​

有人对提高此功能性能的方法有任何建议吗?我相信类的添加/删除占用了大部分的性能开销,所以我特别希望在那里找到效率。

【问题讨论】:

    标签: javascript jquery internet-explorer html-table


    【解决方案1】:
    1. 表本身就是开销,尤其是当它们包含大量内容时。表格也仅在完成时才呈现。如果可能,考虑分页。

    2. 不断的 DOM 操作、重绘(改变外观)和回流(改变尺寸)也是一种开销。

    3. IE6 本身并不是为执行繁重的 JS 操作而构建的。 IE6是什么? 10岁? 10年前的JS是什么?验证和弹出窗口对吗?

    4. 重复的函数调用。在jQuery中,最好缓存$(this)等函数调用的值,而不是重复调用。

    5. 正如我在您的代码中所理解的,您在鼠标悬停期间运行$.each()、切片和一些随机数学运算。太重了。

    6. 考虑使用更新的 jQuery

    另外,我已经清理了你的一些代码:

    $(function() {
        var selecting = false,
            tableContainer = $("#tableContainer"),
            colStart, rowStart;
    
        tableContainer.on("mousedown", 'td', function() {
            var $this = $(this); //reference this
            colStart = $this.index();
            rowStart = $this.closest("tr").index(); //use closest instead of parents to avoid going up to root
            $(".selected", tableContainer).removeClass("selected"); //context instead of find
            $this.addClass("selected");
    
            selecting = true;
        }).on("mouseover", 'td', function() {
            if (selecting) {
    
                var theCell = $(this),
                    colEnd = theCell.index(),
                    rowEnd = theCell.closest("tr").index(), //use closest
                    rowSliceStart = Math.min(rowStart, rowEnd),
                    rowSliceEnd = Math.max(rowStart, rowEnd);
    
                $(".selected", tableContainer).removeClass("selected");
    
                $("tr", tableContainer).slice(rowSliceStart, rowSliceEnd + 1).each(function() {
                    var colSliceStart = Math.min(colStart, colEnd),
                        colSliceEnd = Math.max(colStart, colEnd);
                    $('> *', this).slice(colSliceStart, colSliceEnd + 1).addClass("selected"); //using selector to get children instead of $(this).children()
                });
            }
        }).on("mouseup", 'td', function() {
            selecting = false;
        });
    });​
    

    【讨论】:

    • 不错。也可以缓存所选单元格的列表,以避免在每次鼠标悬停处理程序调用之间再次找到它们..?
    • 还可以保留$("tr", tableContainer)的缓存
    • @Ben 是的,你可以缓存(虽然这很棘手),但由 OP 来构建一个。但是有一个垃圾收集的问题。如果元素在 DOM 中被删除,则对应于该元素的缓存条目也必须手动清空。否则,会发生内存泄漏。
    • 感谢您的提示。不幸的是,IE6 超出了我的控制范围,分页也不是一个选项。我认为数学在性能开销方面基本上是免费的,切片方法是我能想到的最快的方法来获取选定的行/列子集以突出显示。我将查看您在清理后的代码中使用的 jQuery 选择器(和上下文)的文档。那里有一些关于改进我的选择技术的有价值的信息:-)
    【解决方案2】:

    它实际上看起来并不太糟糕。我唯一能想到的就是计算鼠标悬停时的增量。也就是说,存储先前的开始和结束列/行,并在下一个鼠标悬停事件时,仅更新已更改元素的类。

    其他小事:

    • 在 mousedown 处理程序中缓存 $(this)
    • 我不是 100% 确定这个适用于 IE6,但您可以尝试将选择器从 .find('td.selected') 更改为 .find('.selected')。第一个有两个条件要检查,而只有一个。在现代浏览器中,第二个肯定会更快,因为 jQuery 可以利用 getElementsByClassName,但在 IE6 中不存在,所以谁知道呢?
      • 您还可以尝试制作更有针对性的选择器,尤其是当单元格的内容包含更多 DOM 元素时。 .find('> tr > .selected')
    • 限制鼠标悬停处理程序。

    【讨论】:

    • 非常感谢。我会考虑如何处理增量,因为 addClass() 方法肯定具有最大的性能开销,所以如果我可以减少我正在处理的元素数量,它应该会有所帮助。我可以问你限制鼠标悬停处理程序是什么意思吗?设置超时之类的东西更像是悬停?如果是这样,你有什么例子可以说明它是如何工作的吗?
    • @Alex 这是一个用于限制函数的 jQ 插件:benalman.com/projects/jquery-throttle-debounce-plugin 这只是意味着函数不会在每次鼠标悬停时执行,但最多每 X 毫秒执行一次。
    猜你喜欢
    • 2012-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多