5

2つのビューモデルがあり、それぞれが異なるが類似したデータを表す監視可能なプロパティを持っているとします。

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

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

これらのビューモデルは独立しており、必ずしも相互にリンクされている必要はありませんが、場合によっては、3番目のビューモデルがそれらの間にリンクを作成します。

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. このメソッドを使用して、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);場合は正しく機能しません)。site1site2

  3. 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オブザーバsite2ブルを作成してから使用することができますthis.site1().username(this.site2().username());。このメソッドでは、無限ループを回避するために同等性をチェックする必要もあります。オブザーバブルに依存できない場合は、計算内でチェックできますが、更新しているオブザーバブルに別の依存関係を追加します(のようなものobservable.peekが利用可能になるまで)。この方法には、依存関係を設定するために最初に更新コードを1回実行するという欠点もあります(これがcomputed機能するため)。

これらの方法にはすべて欠点があると思うので、これを行う別の方法は、単純(10行未満のコード)、効率的(不要なコードや更新を実行しない)、柔軟性(複数レベルのオブザーバブルを処理する)です。 )?

4

4 に答える 4

7

正確には10行のコードではありませんが(好みに合わせて削除することもできます)、この状況では、ビューモデル間でpub/subメッセージを使用します。

これが私が書いた小さなライブラリです:https ://github.com/rniemeyer/knockout-postbox

基本的な考え方は、ko.subscribableトピックベースのサブスクリプションを作成して使用することです。subscribeToライブラリは、サブスクライブ可能なものを拡張して、、publishOnおよびsyncWith(トピックのパブリッシュとサブスクライブの両方)を追加します。これらのメソッドは、オブザーバブルがこのメッセージングに自動的に参加し、トピックとの同期を維持するための適切なサブスクリプションを設定します。

これで、ビューモデルが相互に直接参照する必要がなくなり、pubsubシステムを介して通信できるようになります。何も壊さずにビューモデルをリファクタリングできます。

私が言ったように、10行未満のコードにそれを取り除くことができます。ライブラリには、サブスクライブを解除できる、公開が実際にいつ行われるかを制御できる(equalityComparer)などの追加機能が追加され、着信値で実行する変換を指定できます。

フィードバックを投稿してください。

基本的なサンプルは次のとおりです:http://jsfiddle.net/rniemeyer/mg3hj/

于 2012-05-30T02:58:54.390 に答える
5

ライアンとジョン、お答えいただきありがとうございます。残念ながら、pub/subシステムに必要なグローバルネーミングシステムを導入したくありません。

subscribeライアン、私はその方法がおそらく最良であることに同意します。サブスクリプションを処理するための一連の関数をまとめました。オブザーバブル自体が動的である可能性がある場合も処理したいので、拡張機能は使用していません。これらの関数は、オブザーバブルまたはオブザーバブルを返す関数のいずれかを受け入れます。ソースオブザーバブルが動的である場合、サブスクライブする固定オブザーバブルを持つように、アクセサー関数呼び出しを計算されたオブザーバブルでラップします。

function subscribeObservables(source, target, dontSetInitially) {
    var sourceObservable = ko.isObservable(source) 
            ? source 
            : ko.computed(function(){ return source()(); }),
        isTargetObservable = ko.isObservable(target),
        callback = function(value) {
            var targetObservable = isTargetObservable ? target : target(); 
            if (targetObservable() !== value)
                targetObservable(value);
        };
    if (!dontSetInitially)
        callback(sourceObservable());
    return sourceObservable.subscribe(callback);
}

function syncObservables(primary, secondary) {
    subscribeObservables(primary, secondary);
    subscribeObservables(secondary, primary, true);
}

これは約20行なので、10行未満という私の目標は少し不合理だったのかもしれません。:-)

上記の関数を示すために、Ryanのポストボックスの例を変更しました:http://jsfiddle.net/mbest/vcLFt/

于 2012-05-30T21:38:21.013 に答える
1

もう1つのオプションは、オブザーバブルのモデルを維持する分離されたデータコンテキストを作成することです。ビューモデルはすべて、データのデータコンテキストを参照し、同じオブジェクトを参照するため、1つが更新されると、すべてが更新されます。VMの依存関係はデータコンテキストにありますが、他のVMには依存していません。私は最近これをやっていて、それはうまくいきました。ただし、pub/subを使用するよりもはるかに複雑です。

単純なpub/subが必要な場合は、彼が言及したRyan Niemyerのライブラリを使用するか、pub / subメッセージング(基本的にはメッセンジャーまたはイベントアグリゲーター)が組み込まれた増幅.jsを使用できます。どちらも軽量で分離されています。

于 2012-05-30T14:56:58.937 に答える
0

誰かが必要な場合に備えて。別のオプションは、参照オブジェクト/オブザーバブルを作成することです。これは、複数のオブザーバブルを含むオブジェクトも処理します。

(function(){
    var subscriptions = [];

    ko.helper = {
        syncObject: function (topic, obj) {
            if(subscriptions[topic]){
                return subscriptions[topic];
            } else {
                return subscriptions[topic] = obj;
            }
        }
    };
})();

ビューモデルで。

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

function site2Model(username) = {
    this.username = syncObject('username', ko.observable());
    this.username(username);
    ....
}
于 2016-03-08T07:41:19.710 に答える