从不同视图模型同步可观察量的简单、干净的方法

2023-11-29

假设我有两个视图模型,每个视图模型都有一个可观察的属性,表示不同但相似的数据。

function site1Model(username) {
    this.username = ko.observable(username);
    ....
}

function site2Model(username) = {
    this.username = ko.observable(username);
    ....
}

这些视图模型是独立的,不一定相互链接,但在某些情况下,第三个视图模型会在它们之间创建链接。

function site3Model(username) = {
    this.site1 = new site1Model(username);
    this.site2 = new site2Model(username);
    // we now need to ensure that the usernames are kept the same between site1/2
    ...
}

以下是我提出的一些选择。

  1. 使用计算的可观察量读取一个并写入两个:

    site3Model.username = ko.computed({
        read: function() {
            return this.site1.username();    // assume they are always the same
        },
        write: function(value) {
            this.site1.username(value);
            this.site2.username(value);
        },
        owner: site3Model
    }
    

    只要更改始终通过计算,这将使值保持同步。但如果直接更改底层可观察量,则它不会这样做。

  2. Use the subscribe相互更新的方法:

    site3Model.site1.username.subscribe(function(value) {
        this.site2.username(value);
    }, site3Model);
    site3Model.site2.username.subscribe(function(value) {
        this.site1.username(value);
    }, site3Model);
    

    只要可观察量在值相同时抑制通知,这种方法就有效;否则你会陷入无限循环。您也可以提前进行检查:if (this.site1.username() !== value) this.site1.username(value);这还有一个问题,即可观察量必须很简单(如果site1 and site2它们本身就是可观察的)。

  3. Use computed进行订阅和更新:

    site3Model.username1Updater = ko.computed(function() {
        this.site1.username(this.site2.username());
    }, site3Model);
    site3Model.username2Updater = ko.computed(function() {
        this.site2.username(this.site1.username());
    }, site3Model);
    

    这种格式允许我们有其他依赖项。例如,我们可以使site1 and site2观察值,然后使用this.site1().username(this.site2().username());此方法还需要检查相等性以避免无限循环。如果我们不能依赖可观察量来做到这一点,我们可以在计算中进行检查,但会添加对我们正在更新的可观察量的另一个依赖项(直到类似observable.peek可用)。 此方法还有一个缺点,即最初运行一次更新代码以设置依赖项(因为这就是computed works).

由于我觉得所有这些方法都有缺点,是否有另一种方法可以做到这一点,该方法简单(少于 10 行代码)、高效(不运行不必要的代码或更新)且灵活(处理多个级别的可观察值) )?


它不完全是 10 行代码(尽管您可以根据自己的喜好将其精简),但对于这种情况,我在视图模型之间使用 pub/sub 消息。

这是我为其编写的一个小型库:https://github.com/rniemeyer/knockout-postbox

基本想法只是创建一个ko.subscribable并使用基于主题的订阅。该库扩展了订阅以添加subscribeTo, publishOn and syncWith(发布和订阅一个主题)。这些方法将为可观察对象设置适当的订阅,以自动参与此消息传递并与主题保持同步。

现在,您的视图模型不需要相互直接引用,并且可以通过 pubsub 系统进行通信。您可以在不破坏任何内容的情况下重构视图模型。

就像我说的,您可以将其精简到不到 10 行代码。该库只是添加了一些额外功能,例如能够取消订阅、能够控制发布实际发生的时间(equalityComparer),并且您可以指定对传入值运行的转换。

请随时发布任何反馈。

这是一个基本示例:http://jsfiddle.net/rniemeyer/mg3hj/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从不同视图模型同步可观察量的简单、干净的方法 的相关文章

随机推荐