38

サブビューのレンダリングを担当するスーパービューがあります。スーパービュー再レンダリングすると、サブビューのすべてのイベントが失われます。

これは例です:

var SubView = Backbone.View.extend({
    events: {
        "click": "click"
    },

    click: function(){
        console.log( "click!" );
    },

    render: function(){
        this.$el.html( "click me" );
        return this;
    }
});

var Composer = Backbone.View.extend({
    initialize: function(){
        this.subView = new SubView();
    },

    render: function(){
        this.$el.html( this.subView.render().el );             
    }
});


var composer = new Composer({el: $('#composer')});
composer.render();

クリックミーdivをクリックすると、イベントがトリガーされます。もう一度実行するcomposer.render()と、すべてがほぼ同じように見えますが、クリックイベントはトリガーされなくなります。

動作しているjsFiddleを確認してください。

4

3 に答える 3

66

これを行うとき:

this.$el.html( this.subView.render().el );

あなたは効果的にこれを言っています:

this.$el.empty();
this.$el.append( this.subView.render().el );

中のすべてのイベントをempty殺しますthis.$el

メモリリークを回避するために、jQueryは、要素自体を削除する前に、データやイベントハンドラーなどの他の構成要素を子要素から削除します。

したがって、delegateイベントをバインドする呼び出しが失われ、イベントが再バインドさthis.subViewSubView#renderません。

あなたはthis.subView.delegateEvents()電話をthis.$el.html()入れる必要がありますが、あなたはそれがの後に起こる必要がありますempty()。あなたはこのようにそれを行うことができます:

render: function(){
    console.log( "Composer.render" );
    this.$el.empty();
    this.subView.delegateEvents();
    this.$el.append( this.subView.render().el );             
    return this;
}

デモ: http: //jsfiddle.net/ambiguous/57maA/1/

またはこのように:

render: function(){
    console.log( "Composer.render" );
    this.$el.html( this.subView.render().el );             
    this.subView.delegateEvents();
    return this;
}

デモ: http: //jsfiddle.net/ambiguous/4qrRa/

または、レンダリング時にremoveを再作成して、this.subViewその方法で問題を回避することもできます(ただし、これにより他の問題が発生する可能性があります...)。

于 2012-08-19T19:18:15.190 に答える
11

そもそもイベント登録を吹き飛ばさない、より簡単な解決策がここにありますjQuery.detach()

http://jsfiddle.net/ypG8U/1/

this.subView.render().$el.detach().appendTo( this.$el );   

ただし、パフォーマンス上の理由から、このバリエーションがおそらく望ましいでしょう。

http://jsfiddle.net/ypG8U/2/

this.subView.$el.detach();

this.subView.render().$el.appendTo( this.$el );

// or

this.$el.append( this.subView.render().el );

明らかに、これは、サブビューが親の唯一のコンテンツである例に一致する単純化です。それが実際に当てはまる場合は、サブビューを再レンダリングするだけで済みます。他のコンテンツがある場合は、次のようなことができます。

var children = array[];

this.$el.children().detach();

children.push( subView.render().el );

// ...

this.$el.append( children );

また

_( this.subViews ).each( function ( subView ) {

  subView.$el.detach();

} );

// ...

また、元のコードで、@ muの回答で繰り返されると、DOMオブジェクトがに渡されますがjQuery.html()、そのメソッドはHTMLの文字列を受け入れるものとしてのみ文書化されています。

this.$el.html( this.subView.render().el );

文書化された署名jQuery.html()

.html( htmlString )

http://api.jquery.com/html/#html2

于 2012-08-20T22:46:36.383 に答える
0

これを使用$(el).empty()すると、選択した要素内のすべての子要素が削除され、選択した要素内の任意の(子)要素にバインドされているすべてのイベント(およびデータ)が削除されます()。el

イベントを子要素にバインドしたまま、子要素を削除するには、次を使用します。

$(el).children().detach();それ以外の$(.el).empty();

これにより、イベントがバインドされて機能している状態で、ビューを正常に再レンダリングできます。

于 2014-03-12T12:50:14.923 に答える