Javascript 值已发生变化,无法按预期工作

Javascript 值已发生变化,无法按预期工作,javascript,knockout.js,Javascript,Knockout.js,我试图在修改可观察数组中对象的值时强制进行UI更新,但数组中的对象不可观察。我假设您可以使用值hassmutated执行此操作,但它并没有像我预期的那样工作 在中,如果单击“更新”按钮,则不会发生任何情况,但如果手动重置阵列,则会更新: 更新 部队更新 var事物=[ {id:1,thing:false}, {id:2,thing:false}, {id:3,thing:false}, {id:4,thing:false} ] var viewModel=函数(){ var self=

我试图在修改
可观察数组中对象的值时强制进行UI更新,但数组中的对象不可观察。我假设您可以使用
值hassmutated
执行此操作,但它并没有像我预期的那样工作

在中,如果单击“更新”按钮,则不会发生任何情况,但如果手动重置阵列,则会更新:


更新 部队更新
var事物=[
{id:1,thing:false},
{id:2,thing:false},
{id:3,thing:false},
{id:4,thing:false}
]
var viewModel=函数(){
var self=这个;
自我观察=可观察的事物;
self.updateValue=函数(){
self.observeThings()[0].id=5;
self.observeThings.valueHasMutated();
}
self.forceUpdate=函数(){
self.observeThings()[0].id=5;
var origThings=self.observateThings();
自我观察(空);
自我观察(原始事物);
}
}
应用绑定(新的viewModel());
valueHasMutated
应该如何工作?

KnockoutJS代码(感谢您的提琴中的调试器版本),在valueHasMutated上执行会导致

evaluateImmediate_CallReadWithDependencyDetection: function (notifyChange) {
// some other code
// ...

// newValue is the same as state.latestValue => "computedObservable["notifySubscribers"]" is not called
        if (computedObservable.isDifferent(state.latestValue, newValue)) {
            if (!state.isSleeping) {
                computedObservable["notifySubscribers"](state.latestValue, "beforeChange");
            }

            state.latestValue = newValue;

            if (state.isSleeping) {
                computedObservable.updateVersion();
            } else if (notifyChange) {
                computedObservable["notifySubscribers"](state.latestValue);
            }
        }
这可以做到:

  self.updateValue = function() {
    var index = 0;
    var item = self.observableThings()[index];
    // Update item content
    item.id = 5;
    // Force array to update markup
    self.observableThings.splice(index, 1);
    self.observableThings.splice(index, 0, item);
  }

但是更好的方法是使用可观察的属性。

将一堆普通对象粘贴到可观察数组中并不能神奇地使这些对象的属性可见

可观察数组通常只观察项目移除和项目插入。如果项目本身有您想要观察的属性,那么这些属性需要显式地变得可观察

政府可以提供帮助。它可以做一些非常好的事情,请阅读文档页面

函数项列表(参数){
var self=这个;
self.things=ko.observearray();
self.updateValue=函数(){
ko.utils.arrayForEach(self.things(),function(thing){
thing.id(~~(Math.random()*100));
});
}
//初始化
fromJS(params,{},self);
}
var vm=新的物品清单({
事情:[
{id:1,thing:false},
{id:2,thing:false},
{id:3,thing:false},
{id:4,thing:false}
]
});
ko.应用绑定(vm)

更新

如果您想多次更改大型observableArray的内容,但仅触发一次更改通知和一次UI更新或其他任何操作,则通常会使用“值已变异”
。因此,您可以对底层数组进行操作,然后在所有更改完成后调用
valueHasMutated

调用
valuehassmutated
没有做任何事情的原因是因为可观察数组的“值”(表示数组中的项,而不是这些项的属性)没有更改。您的调用会导致重新评估阵列的状态-是否添加或删除了任何项?答案是否定的,因此不会发生更改通知

如果您想让您的代码以尽可能小的更改工作,您需要交换一个新项,而不仅仅是更新现有项上的一个属性

self.updateValue = function() {
    var newVal = { id: 5, thing: false };
    self.observableThings()[0] = newVal;
    self.observableThings.valueHasMutated();
  }


最后要说的是,我上面概述的这种情况(即更新数组的许多成员,但只触发单UI更新)实际上是您应该“强制”进行更改通知的唯一原因。如果你不得不做这样的事情,那么你就错了,说“但是我必须重新编写大量的代码”从来都不是不正确做的好理由

这和我的黑客有什么不同?这只是修改数组的另一种攻击。你的攻击会强制重新创建显示数组的所有标记。我的方法将只为一个(更改的)项目更新标记。@mattmanser我的回答说明了-为什么valueHasMutated在您的情况下不起作用,并提出了一个标记更改最少的有效解决方案。为什么被否决?因为这不是问题的答案!我需要所有的项目更新无论如何,所以你的黑客实际上比我的更糟糕。因此,d/v.
valuehassmutated
一词不会出现在此答案中,因为您不需要它。你只是做错了。我回答的核心点是:你需要明确地让你想要观察的一切都可以观察到。映射插件只会自动完成这一步,你不需要使用它。@mattmanser:这篇文章以唯一有意义的方式回答了你的问题:代码实现了你想要的。运行代码段并查看它是否正常工作。它真的不明白这怎么能证明投反对票是正确的。@mattmanser你在读我写的东西吗?看在上帝的份上,你不需要使用映射插件。您使用的敲除错误,这就是代码无法工作的原因。尝试使用
valuehassmutated
是错误的做法,它不会起作用,我已经没有办法用了。让数组中项目的属性可见,一切都会开始工作。我当然不会删除你问题的唯一正确答案。您曾问过“为什么这不起作用?”我向您展示了如何正确操作。“我怎样才能使用
valuehassmutated
使它起作用呢?”这是一种转移注意力、毫无意义的干扰。你甚至不应该尝试这样做,它永远不会起作用,这是错误的做法。老实说,你不能指望我教你怎么做错事。我告诉你如何正确地做,这就是为什么我在这里。你似乎无法摆脱对
valuehassmutated
的痴迷,这是你在这里的主要问题。我为你详细说明了如何按照Knockout的设计来做,没有肮脏的黑客或暴力,也没有映射插件。请参阅修改后的答案。“但我必须重新编写大量代码”永远都不是不正确执行的好理由”谢谢。OP对