knockoutjs深拷贝可观察数组

时间:2018-02-24 11:25:37

标签: javascript knockout.js

我在Knockout中有一个obeservable数组,比如说data包含具有可观察属性的对象。在我的应用程序的一部分中,我想允许用户添加到此数组并最终搞乱它,但如果他们取消将数组恢复到原始状态。

我的一个解决方案是创建一个名为dataCopy的副本,在取消时替换原始数组,但这只会创建另一个指向相同底层数据的指针,因此它也会反映出我做的不是我想要的。 我尝试通过ko.toJS(data)将其转换为javascript,这会创建数据的js数组,但是所有对象都会丢失其可观察属性,而当我使用ko.observableArray(dataCopy)重新创建数据时由于不再能观察到对象的属性,应用程序会崩溃。

如何创建一个knockout数组的克隆而不是另一个指针?

1 个答案:

答案 0 :(得分:3)

这是一个如何使用ko mapping plugin深度复制可观察数组来实现此目的的示例。 我怀疑任何其他复制方法对你都有用,例如.sliceko.toJS,因为正如你所提到的,你需要一个深层拷贝,这个拷贝就像底层对象的可观察属性一样。

这里的重要部分是功能:

function obsArrDeepCopy(from, to) {
  ko.mapping.fromJS(ko.toJS(from), {}, to);
}

首先将源数组转换为计划JS数组然后填充目标数组转换为observable底层对象属性,这将执行深层复制。

完整的工作示例:

function Person(name) { 
  this.name = ko.observable(name);
}

var viewModel = {
    people: ko.observableArray([
        new Person("Annabelle"),
        new Person("Bertie"),
        new Person("Charles")
    ]),
    peopleCopy: ko.observableArray(),
    newName: ko.observable(''),
    addPerson: function() { this.peopleCopy.push(new Person(this.newName())) },
    
    commit: function() { obsArrDeepCopy(this.peopleCopy, this.people) },
    cancel: function() { obsArrDeepCopy(this.people, this.peopleCopy) },
};
 
ko.applyBindings(viewModel);

obsArrDeepCopy(viewModel.people, viewModel.peopleCopy);

function obsArrDeepCopy(from, to) {
  ko.mapping.fromJS(ko.toJS(from), {}, to);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<h2> Initial </h2>
<ul data-bind="foreach: people">
    <li>
        <span data-bind="text: name" /> 
    </li>
</ul>

<br/><br/>

<h2> Copy </h2>
<ul data-bind="foreach: peopleCopy">
    <li>
        <span data-bind="text: name" /> 
    </li>
</ul>


<input type="text" data-bind="textInput: newName" />
<button type="button" data-bind="click: addPerson"> Add </button>

<br/><br/>
<button type="button" data-bind="click: commit"> Commit </button>
<button type="button" data-bind="click: cancel"> Cancel </button>