9

私のビューにはTuneBook、タイプの子ビューがいくつかありますClosedTune。また、曲ごとに個別の全ページビューがありますOpenTuneClosedTune同じイベントがと内にバインドOpenTuneされているため、両方が共有の「抽象」ビューから継承するようにアプリを設計しましたTune

アプリをよりスケーラブルにするために、それぞれのイベントをClosedTune委任しTuneBookたいのですが、保守性のために、同じハンドラー(に格納されているハンドラーTune)を使用しTuneBookたいと思います(ただし、明らかに何らかの関数でラップする必要があります) )。

私が抱えている問題は、ハンドラーを呼び出すためTuneBookの正しいものを見つけることです。ClosedTuneこれを設計するための良い方法は何ですか、またはイベントを親ビューに委任するための他の良い解決策はありますか?

-バックボーンビューの複製ではありません:親からイベントを継承および拡張します(これは、親クラスから継承する子に関するものですが、DOMの親の子ノードである子について質問しています)

4

3 に答える 3

11

親ビュー(からも拡張)では、DOMイベントにBackbone.Eventsバインドします。onEventトリガーすると、子ビューが認識している「id」属性(おそらく行ID?)を含むバックボーンイベントが発生します。

var TuneBook = Backbone.View.extend(_.extend({}, Backbone.Events, {
    events: {
        "click .tune .button": "clickHandler"
    },
    clickHandler: function (ev) {
        this.trigger('buttonClick:' + ev.some_id_attr, ev);
    },

}));

子ビューは、当然、それらに関係する親ビューイベントにサブスクライブします。以下ではinitialize、親ビューと、以前にで使用した特別なid属性を渡すときに行いoptionsます。

var ClosedTune = Backbone.View.extend({

    initialize: function (options) {
        options.parent.on('buttonClick:' + options.id, this.handler, this);
    },

    handler: function (ev) {
        ...
    },

});

Tuneもちろん、またはに同様のサブスクライバーを設定することもできますOpenTune

于 2012-05-07T18:21:38.473 に答える
7

ここにいくつかの可能性があります。

1.一元化:ClosedTuneオブジェクトをTuneBookインスタンスに保存します

  1. それぞれへの参照をに格納しClosedTuneますtune_book.tunes。どのように入力するかtune_book.tunesはあなた次第です。で加算器メソッドについて言及したのでTuneBook、それを以下に示します。

  2. TuneBookイベントハンドラーで、イベントターゲットの属性などをキーとして使用してfromを取得ClosedTuneします。次に、またはハンドラーを呼び出します。tune_book.tunesidTuneClosedTune

http://jsfiddle.net/p5QMT/1/

var Tune = Backbone.View.extend({
  className: "tune",

  click_handler: function (event) {
    event.preventDefault();
    console.log(this.id + " clicked");
  },

  render: function () {
    this.$el.html(
      '<a href="" class="button">' + this.id + '</a>'
    );

    return this;
  }
});

var ClosedTune = Tune.extend({});

var OpenTune = Tune.extend({
  events: {
    "click .button" : 'click_handler'
  }
});

var TuneBook = Backbone.View.extend({
  events: {
    "click .tune .button" : 'click_handler'
  },

  click_handler: function (event) {
    var tune = this.options.tunes[
      $(event.target).closest(".tune").attr('id')
    ];

    tune.click_handler( event );
  },

  add_tune: function (tune) {
    this.options.tunes[tune.id] = tune;
    this.$el.append(tune.render().el);
  },

  render: function () {
    $("body").append(this.el);
    return this;
  }
});

var tune_book = new TuneBook({
  tunes: {}
});

[1, 2, 3].forEach(function (number) {
  tune_book.add_tune(new ClosedTune({
    id: "closed-tune-" + number
  }));
});

tune_book.render();

var open_tune = new OpenTune({
  id: "open-tune-1"
});

$("body").append(open_tune.render().el);

2.分散型:を使用してビューオブジェクトをDOMオブジェクトに関連付けますjQuery.data()

  1. を作成するときはClosedTune、それへの参照を保存しますthis.$el.data('view_object', this)

  2. イベントリスナーで、を取得します。ClosedTune例:$(event.target).data('view_object')

ClosedTune必要に応じて、 (in TuneBook)と、に同じ正確なハンドラーを使用できますOpenTune

http://jsfiddle.net/jQZNF/1/

var Tune = Backbone.View.extend({
  className: "tune",

  initialize: function (options) {
    this.$el.data('view_object', this);
  },

  click_handler: function (event) {
    event.preventDefault();

    var tune =
      $(event.target).closest(".tune").data('view_object');

    console.log(tune.id + " clicked");
  },

  render: function () {
    this.$el.html(
      '<a href="" class="button">' + this.id + '</a>'
    );

    return this;
  }
});

var ClosedTune = Tune.extend({
  initialize: function (options) {
    this.constructor.__super__.initialize.call(this, options);
  }
});

var OpenTune = Tune.extend({
  events: {
    "click .button" : 'click_handler'
  }
});

var TuneBook = Backbone.View.extend({
  events: {
    "click .tune .button": Tune.prototype.click_handler
  },

  add_tune: function (tune) {
    this.$el.append(tune.render().el);
  },

  render: function () {
    $("body").append(this.el);
    return this;
  }
});

var tune_book = new TuneBook({
  tunes: {}
});

[1, 2, 3].forEach(function (number) {
  tune_book.add_tune(new ClosedTune({
    id: "closed-tune-" + number
  }));
});

tune_book.render();

var open_tune = new OpenTune({
  id: "open-tune-1"
});

$("body").append(open_tune.render().el);

コメントへの回答

オプション1を検討しましたが、チューンブックにすでにチューンモデルのコレクションがあり、同期を維持する必要がある別のオブジェクトが必要なかったため、これに反対しました。

どのようなハウスキーピング/同期を行う必要があるか、そしてその理由によって異なります。

(たとえば、TuneModel.remove()で、チューンブックのビューのリストからビューを削除する必要があります...これを行うにはおそらくイベントが必要になるため、イベントのみのソリューションがより魅力的に見え始めます)。

「チューンブックのビューのリストからビューを削除する必要がある」と感じるのはなぜですか。(私はあなたがそうすべきではないことを示唆しているのではなく、なぜあなたがしたいのかを尋ねるだけです。)そうしているので、@ ggozadのアプローチはその点でどのように違うと思いますか?

ClosedTuneどちらの手法も、オブジェクトをTuneBookインスタンスに格納します。@ggozadの手法では、抽象化の背後に隠されているだけなので、おそらくわかりにくくなります。

私の例では、それらはプレーンなJSオブジェクト(tune_book.tunes)に格納されています。@ggozadでは、それらは。_callbacksによって使用される構造に格納されBackbone.Eventsます。

を追加するClosedTune

1.1。

this.options.tunes[tune.id] = tune;

2.2。

this.on('buttonClick:' + tune.id, tune.handler, tune);

を削除したい場合ClosedTune(たとえば、ドキュメントから削除しtune.remove()、ビューオブジェクトを完全に削除したい場合)、@ ggozadのアプローチを使用すると、同じ種類のハウスキーピングを実行しない限り、 ClosedTuneinへの孤立した参照が残ります。tune_book._callbacks私が提案したアプローチを理解する:

1.1。

delete this.options.tunes[tune.id];

tune.remove();

2.2。

this.off("buttonClick:" + tune.id);

tune.remove();

各例の最初の行はオプションですClosedTune。オブジェクトをクリーンアップするかどうかによって異なります。

オプション2は多かれ少なかれ私が今していることですが、(他の理由で)モデルをデータ属性としてview。$ elにも保存しているので、もっと良い方法が必要だと感じずにはいられません。参照をいたるところに保存するよりも。

まあ、それは最終的に物事をどのように構成するかについてのあなたの好みに帰着します。ビューオブジェクトをより集中的に保存したい場合は、TuneBookを使用する代わりにインスタンスに保存できますjQuery.data。#1:集中化を参照してください。

ClosedTune何らかの方法で、オブジェクトへの参照を格納します。を使用してjQuery.data、またはのプレーンオブジェクトで、またはのTuneBookを使用_callbacksTuneBookます。

あなたが理解している理由で@ggozadのアプローチが好きなら、それを選んでください、しかしそれは魔法ではありません。ここに示されているように、#1で示したより単純なバージョンと比較して、追加レベルの抽象化によってどのような利点が提供されるのかわかりません。何か利点があれば、遠慮なく私に記入してください。

于 2012-05-07T17:42:14.267 に答える
0

私がこの記事から取った素晴らしい解決策(@ dave-cadwalladerコメント)。

一般的なバックボーンイベントオブジェクトを拡張し、参照に保存しますvent

var vent = _.extend({}, Backbone.Events);

親ビューに渡します。

var parentView = new ParentView({vent: vent});

子ビューはイベントをトリガーします:

ChildView = Backbone.View.extend({    
  initialize: function(options){
    this.vent = options.vent;
  },

  myHandler: function(){
    this.vent.trigger("myEvent", this.model);
  }
});

そして、親ビューは子イベントをリッスンしています。

ParentView = Backbone.View.extend({    
    initialize: function(options){
        this.vent = options.vent;
        this.vent.on("myEvent", this.onMyEvent);

        let childView = new ChildView({vent: this.vent});
    },

    onMyEvent: function(){
        console.log("Child event has been ");
    }
});

免責事項-ventオブジェクトをすべてのビューに挿入する必要があることに注意してください。この記事では、使用するためのより優れたデザインパターンを見つけることができます。

于 2018-12-09T19:49:27.007 に答える