2013-02-26 57 views
2

在我的viewModel上我有一个名为'bays'的可观察数组,其中包含一个或多个'bay'对象。每个'bay'对象都包含一个名为'products'的可观察数组,它可以包含'product'对象。 随着我的标记看起来像:Knockout.js - 停止在foreach循环中渲染元素

<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,因为支持它们的对象不会改变,而不是破坏产品元素并重新创建它们?

+0

http://jsfiddle.net/mXyzs/16/我添加了一个恼人的警报,但你应该看到的是,对象只创建一次。 – Joe 2013-02-26 19:55:30

+1

一个简单的方法来检查它们是否被重新创建。使用'data-bind =“text:new Date()”'。这将显示元素创建的时间。而不是使用恼人的警报。 – 2013-02-26 22:11:19

+0

@Joe我编辑了我的问题和我的jfiddle,因为我意识到我有点不清楚。我指的是页面上的产品元素被销毁,然后在新的托架中再次创建它们,尽管支持绑定的产品对象没有更改。 – Ric 2013-02-27 12:05:02

回答

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/

0

从外观上看,产品元素不会被重新创建。我在产品对象中添加了创建的属性

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

单击移动到托架按钮时,创建的日期似乎没有改变。它仅仅被添加到另一个可观察数组中,并且该元素被绘制。

有一件事我不会通过。如果你这样做推动到一个可伸缩阵列或从一个循环中的可观察数组弹出或什么,它是昂贵的,你会看到一个性能问题。

瑞安Neimeyer这个位置http://www.knockmeout.net/2012/04/knockoutjs-performance-gotcha.html

希望帮助洽谈! 干杯! Suj