按索引 KnockoutJS 写入的可观察数组

Observable arrays write by index KnockoutJS

我无法通过特定索引写入可观察数组 JS

function AppViewModel()
{
this.curNumber = ko.observable("");
this.numbers = ko.observableArray([0,0,0,0,0,0,0,0,0]);
this.addNumber = function() { this.numbers[this.curNumber]++;}
}
ko.applyBindings(new AppViewModel());

HTML页

<input type="number" data-bind="value: curNumber">
<button data-bind="click: addNumber">Add</button>

我希望当我在输入上写“1”并单击“添加”按钮时,第一个索引值将递增 1,但这对我不起作用

function AppViewModel()
{
    this.curNumber = ko.observable();
    this.numbers = ko.observableArray([0,0,0,0,0,0,0,0,0]);
    this.addNumber = function() { 
        this.numbers()[this.curNumber()]++;
        this.numbers.valueHasMutated();
    }
}

ko.applyBindings(new AppViewModel());

A ko.observableArray 包含原版 Javascript 数组作为值,因此您需要使用 this.numbers()[index] 提取 Javascript 原版数组,注意 (),解包ko.observableArray 值和 returns 该值,一个 Javascript 数组。

在您的代码中,您试图对 ko.observableArray 本身进行数组索引:this.numbers[index]

最后,使用@Kenneth 的回答,如果您的 UI 或其他可观察对象要对您的 addNumber 调用做出反应,您需要让 KnockoutJs 知道 ko.observableArray 已经发生变化,也就是发生了变化在 this.numbers.

上调用 valueHasMutated

最好在 curNumber observable 上使用 subscribe 来监听 curNumber 的变化,并且 subscribe 函数每次都会自动触发你的增量curNumber 变化。

如果适合您的需要,这里是使用 KnockoutJS 的实现 subscribe 并且每次 curNumber 更改。

function AppViewModel()
{
    this.curNumber = ko.observable();
    this.numbers = ko.observableArray([0,0,0,0,0,0,0,0,0]);
    this.curNumber.subscribe(function(newValue) {
        this.numbers()[newValue]++;
        this.numbers.valueHasMutated();
    });
}

现在您不需要调用 addNumber.

的额外步骤

下面只是对 valueHasMutated 的测试,我仔细检查了提取 Javascript 数组并更新数组中的项目是 KnockoutJs 不会观察到的,它是在这种情况下,您必须调用 valueHasMutated() 否则您的数组增量将被 KnockoutJs

忽略

function AppViewModel()
{
  this.curNumber = ko.observable(0);
  this.numbers = ko.observableArray([0,0,0,0,0,0,0,0,0]);
  this.addNumber = function() { 
     resetUI();
     this.numbers()[this.curNumber()]++;
     this.numbers.valueHasMutated();
  }
  
  this.addNumberWithoutHasValueMutated = function() {
     resetUI();
     this.numbers()[this.curNumber()]++;
  }

  this.numbers.subscribe(function(newValue) {
     $('#divStatus').html("true");
  });
}

var viewModel = new AppViewModel(); 
ko.applyBindings(viewModel);

function resetUI() {
  $('#divStatus').html("false");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<label>Array change is observed by Knockout:&nbsp;</label>
<span id="divStatus" style="color: red;">false</span>
<br />
<label>this.numbers() =</label>
<span data-bind="text: numbers()"></span>
<br />
<label>this.curNumber() =</label>
<input type="number" data-bind="value: curNumber" />
<br />
<br />
<button class="reset" data-bind="click: addNumber">Call AddNumber</button>

<br />
<br />
<button class="reset" data-bind="click: addNumberWithoutHasValueMutated">Call AddNumberWithoutHasValueMutated</button>

正如 Brian 在他的回答中所说,数组是可观察的,但数组中的值不是。如果你想触发更新,你必须通过在 observable 上调用 valueHasMutated 来手动完成:

function AppViewModel()
{
    this.curNumber = ko.observable("");
    this.numbers = ko.observableArray([0,0,0,0,0,0,0,0,0]);
    this.addNumber = function() { 
        var index = this.curNumber();
        var arr = this.numbers();
        arr[index] = arr[index] + 1;
        this.numbers.valueHasMutated(); // This tells knockout the value has changed
    }
}

ko.applyBindings(new AppViewModel());

使用此代码,检查 fiddle:Fiddle

this.curNumber = ko.observable("");
this.numbers = ko.observableArray([0,0,0,0,0,0,0,0,0]);
this.addNumber = function() { 
            this.numbers()[parseInt(this.curNumber())] = this.numbers()[parseInt(this.curNumber())]+1;
}

您的代码:

this.numbers[this.curNumber]++

有几个问题:

问题 #1:

this.curNumber 是一个 observable,您必须将它作为一个函数来调用以获取包含在其中的值。

问题 #2

即使你这样做,它仍然不会起作用,因为你从 DOM 得到的值是一个字符串,所以你需要先将它转换为一个数字。

var index = Number(this.curNumber());

问题 #3

this.numbers 不是数组,它是一个 observableArray。你不能直接索引它。

选项 #1

手动进入数组,然后通知值已更改(本质上是

this.numbers()[index]++;
this.numbers.valueHasMutated();

选项 #2

拼接!

splice 方法是在 observableArray 上实现的,它的行为与 the splice method on vanilla JS Arrays 完全一样,而且它会自动通知订阅者。

您可以使用它以这种方式将新项目放置在特定索引上:

array.splice(index, 1, newItem);

意思是:从位置index取出一件物品放入newItem

所以在你的情况下:

this.addNumber = function() {
    var index = Number(this.curNumber());
    var newValue = this.numbers()[index] + 1;
    this.numbers.splice(index, 1, newValue);
}

在 jsfiddle 上查看:

https://jsfiddle.net/czfpbtbv/1