Knockout.js - 停止重新渲染foreach循环中的元素

时间:2013-02-26 19:22:02

标签: javascript knockout.js

在我的viewModel上,我有一个名为'bays'的可观察数组,它包含一个或多个'bay'对象。然后,每个“bay”对象都包含一个名为“products”的可观察数组,该数组可以包含“product”对象。 我的标记看起来像:

<div data-bind="foreach: bays">
    <div class="bay" data-bind="foreach: products">
        <div class="product">
        <!-- Product innards -->
        </div>
    </div>
</div>

如果产品对象从一个托架移动到另一个托架,则产品元素及其内部的所有内容似乎都会被销毁,然后重新创建,如此jfiddle中所示:http://jsfiddle.net/mXyzs/20/

由于我的应用程序可以同时在托架之间移动数百种产品,并且不得不重新创建它们,这导致性能问题。有没有什么方法可以重新使用现有的产品html,看到支持它们的对象没有改变,而不是破坏产品元素并重新创建它们?

2 个答案:

答案 0 :(得分:1)

从Knockout 2.2.0开始,foreach绑定将检测已移动的项目,而不会重新呈现这些项目的UI。但在您的情况下,您将项目从一个数组移动到另一个数组,因此这种优化不适用(因为它只适用于单个foreach绑定)。

为了利用foreach的能力,我们可以将结构展平为一个数组。

var result = [];
ko.utils.arrayForEach(viewModel.bays(), function(bay) {
    ko.utils.arrayForEach(bay.products(), function(product) {
        product.bay(bay);
        result.push(product);
    });
});

如果我们对展平列表使用computed,我们可以在单个foreach绑定中引用它。

<div data-bind="foreach: flattenedProducts">
    <div class="product">
    <!-- Product innards -->
    </div>
</div>

使用此方法,虽然产品将按托架排序,但所有产品div都将是兄弟姐妹。因此,您将无法拥有div每个托架。

示例:http://jsfiddle.net/mbest/3ZUxZ/

答案 1 :(得分:0)

从它的外观来看,产品元素没有被重新创建。我在您的产品对象中添加了一个已创建的属性

var product = function (data) {
    this.name = ko.observable(data.name);  
    this.created = new Date();
};

单击“移动到托架”按钮时,创建的日期似乎不会更改。它只是被添加到另一个可观察的数组中,并且该元素被绘制。

我不会透过一件事。如果您正在执行此推送到可观察数组或从循环中的可观察数组中弹出,则代价很高,您将看到性能问题。

Ryan Neimeyer在这里讨论http://www.knockmeout.net/2012/04/knockoutjs-performance-gotcha.html

希望有所帮助! 干杯! SUJ