Backbone:重新渲染时丢失了事件

fgu*_*len 37 javascript-events backbone.js backbone-events

我有超级视图谁负责渲染子视图.当我重新渲染超视图中的所有事件的子视图都将丢失.

这是一个例子:

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();
Run Code Online (Sandbox Code Playgroud)

当我点击click me div时,会触发事件.如果我composer.render()再次执行,所有内容看起来都很相似,但不会再触发click事件.

检查工作jsFiddle.

mu *_*ort 65

当你这样做:

this.$el.html( this.subView.render().el );
Run Code Online (Sandbox Code Playgroud)

你有效地这样说:

this.$el.empty();
this.$el.append( this.subView.render().el );
Run Code Online (Sandbox Code Playgroud)

empty杀死内部事物的事件this.$el:

为了避免内存泄漏,jQuery在删除元素本身之前从子元素中删除了其他构造,如数据和事件处理程序.

因此,您将失去delegate绑定事件的调用,this.subView并且SubView#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;
}
Run Code Online (Sandbox Code Playgroud)

演示:http://jsfiddle.net/ambiguous/57maA/1/

或者像这样:

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

演示:http://jsfiddle.net/ambiguous/4qrRa/

或者你可以remove重新创建this.subView渲染时并以这种方式回避问题(但这可能会导致其他问题......).


JMM*_*JMM 11

这里有一个更简单的解决方案,它不会首先破坏事件注册:jQuery.detach().

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

this.subView.render().$el.detach().appendTo( this.$el );   
Run Code Online (Sandbox Code Playgroud)

出于性能原因,这种变化可能更可取:

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

this.subView.$el.detach();

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

// or

this.$el.append( this.subView.render().el );
Run Code Online (Sandbox Code Playgroud)

显然,这是一个与示例匹配的简化,其中子视图是父视图的唯一内容.如果确实如此,您可以重新渲染子视图.如果还有其他内容,您可以执行以下操作:

var children = array[];

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

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

// ...

this.$el.append( children );
Run Code Online (Sandbox Code Playgroud)

要么

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

  subView.$el.detach();

} );

// ...
Run Code Online (Sandbox Code Playgroud)

此外,在您的原始代码中,并在@ mu的答案中重复,传递一个DOM对象jQuery.html(),但该方法仅记录为接受HTML的字符串:

this.$el.html( this.subView.render().el );
Run Code Online (Sandbox Code Playgroud)

记录签名jQuery.html():

.html( htmlString )
Run Code Online (Sandbox Code Playgroud)

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