10

バックボーンビューでアラートを2回トリガーする非常に簡単な例を作成しました。

http://jsfiddle.net/feronovak/8svqX/

これは特別なことではありません。個別のビューを正しく呼び出す方法を理解するのは本当に重要なので、前のクリックメソッドをトリガーしません。現在、2つのビューを生成しています。2番目のビューは#boxSearchのフォームを上書きします。[検索]ボタンをクリックすると、アラートも生成されますdoSearch SearchLocation。アラートのみが表示されることを期待していましたdoSearch SearchLatitude。私が間違ったことは何ですか?

var Geo = {
    Views: {},
    Templates: {}
};

Geo.Templates.SearchLocation = _.template( $("#tpl-search-location").html());
Geo.Templates.SearchLatitude = _.template( $("#tpl-search-latitude").html());

Geo.Views.SearchLocation = Backbone.View.extend({
    initialize: function() {
        this.render();
    },
    el: $("#boxSearch"),
    template: Geo.Templates.SearchLocation,
    render: function() 
    {
        $(this.el).html(this.template);
    },
    events: {
        "click input[type=button]": "doSearch"
    },
    doSearch: function(e) {
        e.preventDefault();
        alert('doSearch SearchLocation');
    }
});

Geo.Views.SearchLatitude = Backbone.View.extend({
    initialize: function() {
        this.render();
    },
    el: $("#boxSearch"),
    template: Geo.Templates.SearchLatitude,
    render: function() 
    {
        $(this.el).html(this.template);
    },
    events: {
        "click input[type=button]": "doSearch"
    },
    doSearch: function(e) {
        e.preventDefault();
        alert('doSearch SearchLatitude');
    }
});

$(document).ready(function(e) {
    var searchLocation = new Geo.Views.SearchLocation();
    var searchLatitude = new Geo.Views.SearchLatitude();
});
4

4 に答える 4

19

これは、バックボーンアプリでよく見られる「ゴーストビュー」の問題です。

  • ビューをDOM要素にアタッチします
  • 同じDOM要素に別のビューをアタッチします
  • DOM要素でイベントをトリガーします(さらに悪いことに、両方のビューがリッスンする別の場所でイベントをトリガーします)
  • どちらのビューもイベントハンドラーを起動し、大混乱を引き起こすことがよくあります。

@machineghostが指摘しているように、コードには最初のビューのバインドを解除するものがないため、両方のビューがにアタッチされ#boxSearch、両方のビューがイベントに応答しますclick。これを回避する方法はいくつかあります。

  • e.stopPropagation()イベントハンドラーで(docs )を呼び出すことができます(これがあなたがやろうとしていることだと思いますe.preventDefault())。これにより、イベントがトリガーされるとイベントがバブリングするのを防ぐことができるため、最後に定義されたビューがイベントをキャッチします。これは機能しますが、2つのビューがまだぶら下がっていて、古いゴーストビューには他の副作用がある可能性があることに注意してください。

  • 各ビューに、クラスを使用して独自のDOM要素をレンダリングさせてから、不要になったものを.boxSearch呼び出すことができます。view.remove()これはおそらく最もクリーンなオプションですが、ほとんどのDOMをその場で作成することを意味します。これは、HTMLでコーディングするよりも少しコストがかかり、管理が困難です。

  • 各ビューにクリーンアップメソッドを指定できます。たとえば.clear()、またはを.exit()呼び出すことができます。次に、ビューが終了したら、必ずこのメソッドを呼び出してください。view.undelegateEvents()view.stopListening()

それが呼び出されることを確認し、クリアする必要があるすべてをクリアすることを確認することに注意している場合、それはうまく機能します。

于 2013-03-26T00:20:08.903 に答える
2

要素に別のビューを追加しても、古いビューは自動的に削除されません。それをしたい場合は、明示的にを呼び出す必要がありますyourFirstView.remove()。ただし、これを行うと要素も削除されます。要素を削除せずにイベントのバインドを解除したいだけの場合は、yourFirstView.undelegateEvents()代わりに使用できます。

これはバックボーンの意図的な動作であることに言及する価値があります。多くの場合、1つのビューで2つ以上のビューを持つことができると便利elです。

于 2013-03-25T23:17:53.527 に答える
0

バックボーンがjQuery(またはZepto ...のいずれか、jQueryを想定し、必要に応じて置換できるようにする)を使用してイベントをビュー内の要素にバインドすると、イベントが要素から要素にバブルアップしたかのようにイベントをel処理します。

delegateEvents注釈付きのソースで、この動作がどこから来ているのかを知ることができます。

http://documentcloud.github.com/backbone/docs/backbone.html

delegateEvents: function(events) {
  if (!(events || (events = _.result(this, 'events')))) return this;
  this.undelegateEvents();
  for (var key in events) {
    var method = events[key];
    if (!_.isFunction(method)) method = this[events[key]];
    if (!method) continue;

    var match = key.match(delegateEventSplitter);
    var eventName = match[1], selector = match[2];
    method = _.bind(method, this);
    eventName += '.delegateEvents' + this.cid;
    if (selector === '') {
      this.$el.on(eventName, method);
    } else {
      this.$el.on(eventName, selector, method);
    }
  }
  return this;
},

this.$el.on(eventName, method);重要なのは、およびに関する「委任可能な」イベントを理解することです。 this.$el.on(eventName, selector, method);

jQueryについては、http://api.jquery.com/on/の「直接および委任されたイベント」のセクションを参照してください。

コードに関しては、なぜそれがそのまま動作しているのかがわかるといいのですが。el要素自体を上書きしていないため、委任された両方のバインディングは引き続き有効です。

于 2013-03-25T23:58:51.293 に答える
0

ビュー階層によってリスナーのバインドが重複しないようにしたい場合があります。たとえば、サブULを備えたULを備えたツリーのようなビューがある場合です。そして、これらのULはDOMに存在し、バックボーンビューを;;内のボタンにバインドする必要があります。LI。次に、> "の助けを借りて、つまり次の代わりに、より厳密なセレクターを使用する必要があります。

"click li .btn": "handleClick"

あなたが持っているだろう:

"click li > .btn": "handleClick"
于 2016-02-15T20:25:12.543 に答える