最小化 jquery.append 重站点的 DOM 访问

Posted

技术标签:

【中文标题】最小化 jquery.append 重站点的 DOM 访问【英文标题】:Minimizing DOM access for jquery.append heavy site 【发布时间】:2015-09-30 21:56:24 【问题描述】:

这里有一段代码代表了我编写网站的一般风格:

!function()
    window.ResultsGrid = Class.extend(function()

        this.constructor = function($container, options)
            this.items = [];
            this.$container = $($container);
            this.options = $.extend(, defaultOptions, options);

            this.$grid = $(
                '<div class="results-grid">\
                    <ul></ul>\
                </div>'
            )
                .css("margin", -this.options.spacing / 2);

            this.$list = this.$grid.find("ul");

            this.$container.append(this.$grid);
        ;


        this.setItems = function(datas) 
            this.$grid.addClass("display-none");
            this.clear();
            for (var k in datas) this.addItem(datas[k]);
            this.$grid.removeClass("display-none");
        ;

        this.addItem = function(data) 
            var width = this.options.columnWidth;
            var height = this.options.rowHeight;
            var padding = this.options.spacing / 2;
            if (this.options.columns > 0) width = (this.$container.width() - this.options.columns * this.options.spacing) / this.options.columns;
            if (this.options.rows > 0) height = (this.$container.height() - this.options.rows * this.options.spacing) / this.options.rows;
            if (this.options.ratio > 0) height = width / this.options.ratio;
            var item = new (this.options.class)(this.$list, 
                data: data,
                type: this.options.type,
                width: width,
                height: height,
                padding: padding
            );
            this.items.push(item);
        ;

        this.clear = function() 
            for (var k in this.items) this.items[k].destroy();
            this.items.length = 0;
        ;

        this.destroy = function() 
            this.clear();
            this.$grid.find("*").off();
            this.$grid.remove();
        
    );

    var defaultOptions = 
        class: ResultsItem.Game,
        type: ResultsItem.Game.COMPACT,
        columns:1,
        rows:0,
        spacing: 10,
        rowHeight: 80,
        ratio: 0,
        columnWidth: 0
    ;

();

这是我用于项目列表的东西,它只是一个基类,所以看起来毫无意义。 在我的主页上,我有一些这样的“ResultsGrids”,总共有大约 100 项要添加。这些项目中的每一个都对其代表的 jquery 对象调用 append、addClass、css 等大约 5 次,因此在呈现之前需要进行大量的 html 摆弄。 问题是,有一个相当明显的时间延迟,因为我刚刚明白我通过为每个项目调用 jquery.append 之类的方法来访问 DOM 的次数是不必要的。

显而易见的解决方案是通过连接每个项目的 html 字符串为每个 ResultsGrid 做一个大附加,但我想知道这和我当前的方法之间是否有一个中间立场,它会表现得一样好,否则我会有重写很多代码。

我喜欢从 $("") 开始并一点一点地追加,但显然这在性能方面并不好,因为它不断地重新计算东西,但我不需要知道宽度、高度和位置每一步的一切。理想情况下,我想告诉它在我告诉它之前不要对 DOM 做任何事情。如果无法使用 jquery 执行此操作,那么我想要一个允许我执行此操作的库。 我已经简要了解了 js 模板库,但它们看起来并不是很诱人。尤其是 Angular。

【问题讨论】:

我在您包含的代码中只看到一个.append(),因此很难理解您要修复哪些.append() 操作。 【参考方案1】:

我不知道你想要做什么,但据我了解,你可以尝试使用 jquery 的 $.detach() 函数。

this.setItems = function(datas) 
            //store the parent of this grid                
            this.parent = this.$grid.parent();
            this.$grid.detach();
            this.$grid.addClass("display-none");
            this.clear();

            //here you add your html/etc to the grid
            for (var k in datas) this.addItem(datas[k]);

            //reattach the grid to the parent
            this.parent.append(this.$grid);
            this.$grid.removeClass("display-none");
        ;

对分离的元素进行 DOM 操作应该会更快,并为您提供如您所想的中间解决方案。 这是一个性能提示,您可以找到 here,以及其他一些有用的提示。

【讨论】:

当一个 jq 对象被分离时,它仍然链接到一个 Dom 片段,当它被改变时,它会重新计算尺寸等等,对吧?我想知道是否有一个库可以让我一点一点地创建 dom 元素,但无需接触 dom 或做任何无关的工作(直到我最终想将它添加到 dom 中) 分离时,元素不链接到 DOM,jquery 处理所有更改并且速度更快,因为 DOM 不需要在每次修改时更新其所有结构。您使用 jquery 所做的已经在 DOM 之外创建元素,相当于 document.createElement(),只有当您将项目附加到另一个 DOM 元素时,它才会“触及”DOM。 啊,现在明白了(我想)。我被误解所困扰。一些快速测试表明,分离节省了大量时间,谢谢!

以上是关于最小化 jquery.append 重站点的 DOM 访问的主要内容,如果未能解决你的问题,请参考以下文章