【发布时间】:2012-10-25 06:24:32
【问题描述】:
基本上我有一个 observableArray 并且每个项目的值都不是可观察的。这意味着当我更改项目值时,observableArray 的 foreach 循环中的 UI 不会相应更新。
如果我必须将它们设置为可观察,这意味着巨大的变化,那么有没有一种方法可以手动刷新 UI 或 observableArray foreach?
【问题讨论】:
标签: knockout.js
基本上我有一个 observableArray 并且每个项目的值都不是可观察的。这意味着当我更改项目值时,observableArray 的 foreach 循环中的 UI 不会相应更新。
如果我必须将它们设置为可观察,这意味着巨大的变化,那么有没有一种方法可以手动刷新 UI 或 observableArray foreach?
【问题讨论】:
标签: knockout.js
是的,您可以为您的数组调用valueHasMutated 函数:
yourArray.valueHasMutated();
编辑: 如果首先没有帮助,您可以进行“脏”刷新:
self.refresh = function(){
var data = self.array().slice(0);
self.array([]);
self.array(data);
};
【讨论】:
var data = self.array();self.array(null);self.array(data);
当你有一个包含不可观察元素的可观察数组,并且数组中某个元素的某些属性发生变化时,如果你只想刷新那个元素,你可以使用indexOf和splice,像这样:
var changedIdx = obsArray.indexOf(changedItem);
obsArray.splice(changedIdx , 1); // removes the item from the array
obsArray.splice(changedIdx , 0, changedItem); // adds it back
它的作用是在数组中查找元素,将其删除,然后将其重新插入。当它被插入回来时,元素会再次绑定新值。
如果你喜欢这个解决方案,你可以扩展所有 ko 可观察数组的功能,像这样:
ko.observableArray.fn.refresh = function (item) {
var index = this['indexOf'](item);
if (index >= 0) {
this.splice(index, 1);
this.splice(index, 0, item);
}
}
然后,当您更改数组的一项时,您只需进行以下调用:
obsArray.refresh(changedItem);
如果您的数组中有许多元素,您将获得与 Artem Vyshniakov 的 dirty 刷新相关的改进性能,它会更新数组中所有元素的绑定,而不仅仅是更改的元素。
注意:valueHasMutated,除了没有记录(我想是供内部使用),只检查数组本身是否发生了变化,而不是数组中不可观察的元素是否发生了变化,所以它不起作用。 IE。它只检测您是否向数组中添加了元素、从数组中删除了元素、使用新的不同元素更改了数组的元素,或者更改了元素的顺序。但它不会检查元素本身是否发生了变化
【讨论】:
obsArray.indexOf() 使用 === 查找与它的值匹配的元素,但在 javascript 中 {'x': 'X'} === {'x': 'X'} 返回 false
indexOf 会找到它。如果更改了不在数组中的对象,则必须将数组中的对象替换为新对象,这与更改数组中的元素的属性并通知它是不同的变了,另一种情况完全不同。
我最终使用了上面的脏方法,但这样做是为了让我的所有可观察数组都具有此功能。
ko.observableArray.fn.refresh = function () {
var data = this().slice(0);
this([]);
this(data);
};
valueHasMutated 对我不起作用。整个列表都必须更新,这有点蹩脚。或者在我的情况下,找到一种方法来扩展 ko 映射插件以用可观察对象填充可观察数组..
【讨论】:
var data = this()/*.slice()*/;this(null);this(data); 也能正常工作,甚至更快
我通过替换数组中的整个对象找到了一个简单的解决方案。
在此示例中,参数ix 是索引,oLine 是更新后的对象,oVM.objProps.lines 包含数组。该解决方案非常有效。
/* This contortion causes the computed function to fire because
* we have replaced the entire line object.
*/
function forceRefresh(ix,oLine) {
var oVM = pme.getVM();
oLine = JSON.parse(JSON.stringify(oLine));
oVM.oObjProp.lines[ix] = oLine;
}
【讨论】:
我正在使用带有 deferUpdates 的 Knockout,而 JotaBe 的解决方案需要更新。
似乎 Knockout 在删除/添加时检测到这是同一个项目,因此不要刷新数组。
我采用了以下解决方案:
ko.observableArray.fn.refresh = function (item, index) {
if (index==null) index = this['indexOf'](item);
if (index >= 0) {
this.splice(index, 1, ko.utils.extend({}, item)) // create new item
//this.splice(index, 1);
//this.splice(index, 0, item);
}
}
它会正确刷新数组! :-)
注意,我在 refresh 函数中添加了第二个参数,用于在给定索引时指定索引,以避免 indexOf 运行。
【讨论】: