Backbone.js :重新渲染时丢失事件

ffscu2ro  于 2022-11-24  发布在  其他
关注(0)|答案(3)|浏览(176)

我有一个负责渲染 * 子视图 * 的 * 超级视图 。当我 * 重新渲染**超级视图 * 时, 子视图 * 中的所有事件都将丢失。
这是一个例子:

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(),一切看起来都很相似,但是 *click事件 * 不再被触发。
检查working jsFiddle

wz3gfoph

wz3gfoph1#

执行此操作时:

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

你实际上是在说:

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

并且empty终止this.$el内所有对象上的事件:
为了避免内存泄漏,jQuery在删除元素本身之前,会从子元素中删除其他结构,如数据和事件处理程序。
因此,您丢失了绑定this.subView上的事件的delegate调用,并且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,这样就可以避开问题(但这可能会导致其他问题...)。

33qvvth1

33qvvth12#

这里有一个更简单的解决方案,它一开始就不会把活动注册吹走: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

huwehgph

huwehgph3#

当使用$(el).empty()时,它会删除选定元素中的所有子元素**,并删除所有绑定到选定元素(el)内任何(子)元素事件**(和数据)。
若要保留系结至*子项目**的事件,但仍要移除子项目,请用途:
$(el).children().detach();而不是$(.el).empty();
这将允许您的视图成功地重新呈现,并且事件仍在绑定和工作。

相关问题