我有以下组件:
<template id="fruits-tpl">
<p>Name: <input data-bind="value: name" /></p>
<p>Type: <input data-bind="value: color" /></p>
</template>
ko.components.register('fruits', {
viewModel: function(params) {
this.name = params.name;
this.color = params.color;
},
template: { element: 'fruits-tpl' }
});
我正在将这个组件与下面的视图模型一起使用,其中我的可观察列表中的项目属于不同的类型并具有不同的属性:
function Fruit(data) {
this.name = ko.observable(data.name);
this.color = ko.observable(data.color);
}
function Dessert(data) {
this.name = ko.observable(data.name);
this.packaging = ko.observable(data.packaging);
}
function Vm(){
var data = [{name:"Apples",color:"Yellow"},{name:"Cookies",packaging:"Box"}];
this.items = ko.observableArray([new Fruit(data[0]),new Dessert(data[1])]);
this.items.choice = ko.observable(this.items()[0]);
}
每当我更改输入框中的文本时,此组件就会很好地工作,并且基础数据也会更新:
<div data-bind="component: {name: 'fruits', params: items.choice}"></div>
现在,我想将可观察对象的逻辑封装到组件本身中,因此我以这种方式更改了组件:
ko.components.register('fruits', {
viewModel: function(params) {
this.name = ko.observable(params.name);
this.color = ko.observable(params.color);
},
template: { element: 'fruits-tpl' }
});
...现在我只在内部有可观察的item.choice数据:
function Vm(){
var data = [{name:"Apples",color:"Yellow"},{name:"Cookies",packaging:"Box"}];
this.items = ko.observableArray(data);
this.items.choice = ko.observable(this.items()[0]);
}
为什么我的第二个示例中的主视图模型中的基础数据没有更新,尽管item.choice仍然可以观察到?我确定我缺少一些概念,也许我的可观察数组中的每个项目也应该是可观察的,但是我不知道是否有办法使第二个示例工作。
第一个示例:http : //jsfiddle.net/5739ht0q/2/第二个示例:http : //jsfiddle.net/079tx0nn/
有几种方法可以将数据更新回主视图模型,如下所示。
但是首先,让我们稍微完善一下主视图模型。
function Vm(data) {
var self = this;
self.items = ko.observableArray(ko.utils.arrayMap(data, function(item) {
return ko.observable(item);
}));
self.items.choice = ko.observable(0);
self.items.choice.data = ko.computed(function() {
return self.items()[self.items.choice()];
});
}
第一种快速且肮脏的方法是将在主视图模型内部定义的函数传递给组件:
<div data-bind="component: {
name: 'fruits',
params: {index: items.choice(), data: items.choice.data(), update: items.update}
}"></div>
在组件内部,我们可以调用函数来保存更改:
self.data = ko.computed(function(){
params.update(params.index, ko.toJS(self));
});
现在,主视图模型中的更新功能显而易见,无需为此花费更多的时间。
第二种方法是使用可订阅的对象沿视图模型建立通信:
ko.intramodels = new ko.subscribable();
从组件,发送通知:
self.data = ko.computed(function(){
ko.intramodels.notifySubscribers(ko.toJS(self), "updateFruits");
});
主视图模型内的订阅将接收并保存更改,或多或少是这样的:
ko.intramodels.subscribe(function(newValue) {
self.items.replace(self.items()[self.items().index], newValue);
}, self, "updateFruits");
当然这可以通过手工完成上面一样,但伟大的瑞恩·尼迈耶的邮筒库将是最佳的选择,在这里:https://github.com/rniemeyer/knockout-postbox。
我测试了这两种解决方案,但是不幸的是,当我激活-淘汰赛3.4中的新功能-推迟更新选项时遇到了一些麻烦:ko.options.deferUpdates = true;
当我收到“超出最大调用堆栈大小”错误时。
因为我不想放弃并错过淘汰赛3.4的这一新的出色性能增强功能,并且由于此错误也或多或少地意味着,
循环依赖关系是设计错误,请重新考虑实现的某些部分,
我更改了视图模型,以使依赖项跟踪链仅在一个方向上起作用,而对整个组件数据仅使用一个可观察的模型:
ko.components.register('fruits', {
viewModel: function(params) {
var self = this;
self.data = params.peek();
self.item = {};
self.item.name = ko.observable(self.data.name);
self.item.color = ko.observable(self.data.color);
self.update = ko.computed(function() {
params(ko.toJS(self.item));
});
},
template: {
element: 'fruits-tpl'
}
});
到目前为止,对于嵌套组件而言,这更明显了,这些组件内部具有所有数据处理和可观察的创建,并且主视图模型不必了解子级内部的内容以及原因-只需传递和接收即可。返回一个可观察对象:
<div data-bind="component:{name:'fruits',params:items.choice.data}"></div>
<template id="containers-tpl">
<div data-bind="foreach: containers">
<p><input data-bind="textInput: quantity"><span data-bind="text: name"></span></p>
</div>
</template>
<template id="fruits-tpl">
<p>Name:<input data-bind="textInput: item.name"></p>
<p>Color:<input data-bind="textInput: item.color"></p>
<div data-bind="component:{name:'containers',params:item.containers}"</div>
</template>
这里的关键点是:
带有嵌套组件的完整提琴:http : //jsfiddle.net/jo37q7uL/
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句