如果您在一个页面上有多个视图模型,那么如何确保它们可以保持同步? 例如,如果添加了一个项目或者在一个视图模型上单击了一个按钮,并且您希望其他视图模型对该更改敏感,那么Knockout可以本机地管理它,还是使用某些消息传递或发布/订阅体系结构更好。 / p>
我希望远离管理模型之间的可观察性。
答案 0 :(得分:26)
Knockout 2.0确实包含允许您执行基本发布/订阅的功能。以下是两个视图模型通过中介进行通信的示例。
var postbox = new ko.subscribable();
var ViewModelOne = function() {
this.items = ko.observableArray(["one", "two", "three"]);
this.selectedItem = ko.observable();
this.selectedItem.subscribe(function(newValue) {
postbox.notifySubscribers(newValue, "selected");
});
};
var ViewModelTwo = function() {
this.content = ko.observable();
postbox.subscribe(function(newValue) {
this.content(newValue + " content");
}, this, "selected");
};
ko.applyBindings(new ViewModelOne(), document.getElementById("choices"));
ko.applyBindings(new ViewModelTwo(), document.getElementById("content"));
第一个视图模型通过邮箱通知特定主题,第二个视图模型订阅该主题。他们没有直接相互依赖。
当然,邮箱不需要是全局的,可以传递给视图模型构造函数,也可以只在自执行函数中创建。
示例:http://jsfiddle.net/rniemeyer/z7KgM/
此外,postbox
可能只是ko.observable
(包括ko.subscribable
个功能)。
答案 1 :(得分:0)
你似乎正朝着矛盾的目标前进。你在Knockout中这样做的方法是创建可观察的,但你似乎并不想要那样。
如果你有带有observables的Foo和Bar对象,你可能不希望Foo上的observable与bar或者反之亦然,但为什么没有一个Widget可以观察Foo和Bar并进行调解?
答案 2 :(得分:0)
我为我最近的一个项目创建了一个小扩展来解决这个问题。在方法论上稍微类似,但直接添加对已发布的observable的订阅,并且如果在声明已发布的observable之前声明,则将对订阅者进行排队。
答案 3 :(得分:0)
我发现同步模型的方法是使用RP Niemeyer
的邮箱库然而,我发现有关observableArray的一些有趣内容。这就是我创建新答案的原因。只是为了完成尼迈耶的答案。
使用postbox和observableArray时,在observableArray中添加或删除元素时会触发“subscribeTo”和“publishOn”事件。更新数组中的元素时,它不会触发任何内容。我认为这与邮箱库没有任何关系,只是淘汰限制。
如果您在更新可观察数组的元素时尝试获取事件,最好使用邮箱库中的“发布”和“订阅”方法。
请参阅以下FIDDLE
代码参考:
function FundEntity (fund)
{
var self = this;
self.id = fund.id;
self.fundName = fund.fundName;
self.description = fund.description;
self.isFavorite = ko.observable(fund.isFavorite);
}
function GridViewModel(model) {
var self = this;
self.fundList = ko.observableArray();
model.funds.forEach(function(fund) {
self.fundList.push(new FundEntity(fund));
});
self.favorite = function (id, index) {
var newValue = {
id: id,
index: index,
isFavorite: self.fundList()[index].isFavorite()
};
ko.postbox.publish("itemChanged", newValue);
return true;
};
self.isEditable = ko.observable().subscribeTo("myEditableTopic");
}
function FundDetailViewModel(model) {
var self = this;
self.fundList = ko.observableArray();
model.funds.forEach(function(fund) {
self.fundList.push(new FundEntity(fund));
});
ko.postbox.subscribe("itemChanged", function (newValue) {
self.fundList()[newValue.index].isFavorite(newValue.isFavorite);
});
self.editable = ko.observable(false).publishOn("myEditableTopic");
}