14

如果您在一页上有多个视图模型,如何确保它们保持同步?例如,如果在一个视图模型上添加了一个项目或单击了一个按钮,并且您希望另一个视图模型对该更改敏感,那么 Knockout 可以本地管理它,还是使用一些消息传递或发布/订阅架构更好。

我想远离必须管理模型之间的 observables。

4

4 回答 4

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功能)。

于 2012-03-27T15:28:12.097 回答
0

我为我最近的一个项目创建了一个小扩展来解决这个问题。方法上略有相似,但直接将订阅添加到已发布的 observable,如果在已发布的 observable 声明之前声明,则会将订阅者排队。

淘汰赛 PubSub

于 2012-05-03T16:38:26.457 回答
0

你似乎正朝着相互矛盾的目标前进。您在 Knockout 中执行此操作的方式是创建 observables,但您似乎并不希望这样做。

如果您有带有可观察对象的 Foo 和 Bar 对象,您可能不希望 Foo 上的可观察对象与 bar 交互或反之亦然,但为什么不拥有一个监视 Foo 和 Bar 并进行调解的 Widget?

于 2012-03-27T15:13:22.883 回答
0

我发现同步模型的方法是使用RP Niemeyer的邮箱库

但是我发现了一些关于 observableArray 的有趣的东西。这就是我创建新答案的原因。只是为了完成尼迈耶的回答。

使用邮箱和 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");
}
于 2015-11-12T14:59:24.567 回答