Backbone: ビューを2回インスタンス化するときにイベントが重複する

作成日 2012年02月05日  ·  9コメント  ·  ソース: jashkenas/backbone

ビューを(Backbone.View.extendを介して)定義し、それを2回(newを介して)インスタンス化すると、各iviesオブジェクトでイベントが1回発生すると、2回発生します。

簡単な例:

<html>
<head>
    <script type="text/javascript" src="js/jquery-1.7.1.js"></script>
    <script type="text/javascript" src="js/underscore-1.3.1.js"></script>
    <script type="text/javascript" src="js/backbone-0.9.1.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/javascript">
        testview = Backbone.View.extend ({
            el: '#test',
             events: {'click .test': 'doTest'},
             doTest: function() {alert('test')},
             render: function() {$('#test').append($('<a>').attr('href', '#').addClass('test').append('test'));}});
        view_one = new testview;
        view_two = new testview;
        view_one.render();
    </script>
    </body>
</html>

全てのコメント9件

好奇心から、なぜそれを2回インスタンス化するのですか? モバイルビューなど、ビューポートの最初のインスタンスが別のビューに置き換えられており、ユーザーがその最初のビューに戻ったときに、二重バインディングが発生していますか?

そんな感じ。 ホームビューがあり、ユーザーがログインしているかどうかに関係なく、さまざまなエンドポイントを呼び出します。 イベントバインディングは、ログイン/ログアウトボタン用です。 両方のビューがインスタンス化されますが、一度にレンダリングされるのは1つだけです。 彼らがログインまたはログアウトするとき、私は同じビューに切り替えますが、異なるモードになります。 それが十分に明確であることを願っています。

両方のビューが同時にインスタンス化される理由は、まだ完全にはわかりません。 両方がdom内の同じ既存の要素にバインドされるということは、二重のイベントが発生することを意味します。 これは実際にはバグではありませんが、イベント、特にイベントの委任が機能する方法です。

既存の要素のビューをインスタンス化する場合は、それらのイベントのバインドを明確に解除する必要があります。そうしないと、要素ノード自体がDOMから削除されるまでイベントが保持されます。

さて、初期化中に両方のビューをインスタンス化し、両方をDOMの同じルート要素にバインドしてから、ログインモードに従って一方または他方をレンダリングし、レンダリング中に他方の要素を置き換えるのは良い考えのように思えました。 あなたのコメントから、それを行うためのより良い方法があると思います。

必要なときにビューをインスタンス化します。 ビューが使用されていない場合は、メモリを占有し、見ているような副作用を引き起こす可能性があるため、ビューを使用する必要はありません。

私はこのパターンを使用しない傾向があります:

var View = Backbone.View.extend ({
    el: '#test',
    events: 
    {
        'click .test': 'onClick'
    },
    onClick: function(event) 
    { 
        ... 
    }
});

view = new View;
view.render();

しかし、代わりに、イベントの重複をもたらすゾンビビューを避けるために、このパターンを使用する傾向があります

var View = Backbone.View.extend ({
    events: 
    {
        'click .test': 'onClick'
    },
    onClick: function(event) 
    { 
        ... 
    }
});

view = new View;
$('#target').append(view.render().el);

最初のパターンを使用する唯一の場所は、GUIをインスタンス化するアプリケーションのChromeビューです。

var Application = Backbone.View.extend({
    el: '#wrapper',
    initialize: function (options)
    {
        this.render();
    }
)};

$(document).ready(function () {
    window.application = new Application();
});

@vincentbrigliaがelを定義せず、ビューに独自の要素を生成させることについて述べたことと同じです。 私も95%の時間それをします。 ただし、 elを定義し、削除時にイベントをクリーンアップする場合は、対応するすべてのon()に対して.off()を使用して独自のBackbone.View.destroy()メソッドを定義できます。そしてevents: {}すべてのイベント

例えば:

var MyView = Backbone.View.extend({

  initialize: function() {
    this.model.on('change', this.render, this);
  },

  render: function() {
    return this;
  },

  destroy: function() {
    this.remove();
    this.model.off('change', this.render, this);
  }
})

ありがとう、 @ malandrew@vincentbriglia 、それは本当に役に立ちます。

後世のためにこれを更新するために...このようなViewクラスにdestroyメソッドを追加しました

           destroy: function() {
                this.undelegateEvents();
            }

次に、instantiate()を実行するたびに、現在のビュー(State.view)を破棄します。

このページは役に立ちましたか?
0 / 5 - 0 評価

関連する問題

inf3rno picture inf3rno  ·  17コメント

rafde picture rafde  ·  9コメント

g00fy- picture g00fy-  ·  9コメント

zowers picture zowers  ·  11コメント

gfranko picture gfranko  ·  18コメント