我在Knockout中有一个obeservable数组,比如说data
包含具有可观察属性的对象。在我的应用程序的一部分中,我想允许用户添加到此数组并最终搞乱它,但如果他们取消将数组恢复到原始状态。
我的一个解决方案是创建一个名为dataCopy
的副本,在取消时替换原始数组,但这只会创建另一个指向相同底层数据的指针,因此它也会反映出我做的不是我想要的。
我尝试通过ko.toJS(data)
将其转换为javascript,这会创建数据的js数组,但是所有对象都会丢失其可观察属性,而当我使用ko.observableArray(dataCopy)
重新创建数据时由于不再能观察到对象的属性,应用程序会崩溃。
如何创建一个knockout数组的克隆而不是另一个指针?
答案 0 :(得分:3)
这是一个如何使用ko mapping plugin深度复制可观察数组来实现此目的的示例。
我怀疑任何其他复制方法对你都有用,例如.slice
或ko.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>