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();

当我单击click me 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.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并以这种方式回避问题(但这可能会导致其他问题......)。

于 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 回答