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

时间:2012-08-19 18:17:39

标签: javascript-events backbone.js backbone-events

我有 super-View 负责渲染子视图。当我重新渲染 超级视图时,子视图中的所有事件都将丢失。

这是一个例子:

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(),则所有内容看起来都相同,但 click事件不再被触发。

检查working jsFiddle

3 个答案:

答案 0 :(得分:64)

执行此操作时:

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

你实际上是在说这个:

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

empty会杀死this.$el内所有内容的事件:

  

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

因此,您失去了delegatethis.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;
}

演示: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并以这种方式回避问题(但这可能会导致其他问题......)。

答案 1 :(得分: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

答案 2 :(得分:0)

使用$(el).empty()时,它会移除所选元素中的所有子元素并删除所有 绑定到的事件(和数据)所选元素(el)内的任何(子)元素

将事件绑定 子元素,但仍然删除子元素,请使用:

$(el).children().detach();代替$(.el).empty();

这将允许您的视图成功重新呈现仍然绑定并正常工作的事件。