Backbone.View:delegateEvents不会将事件重新绑定到子视图

时间:2014-01-09 21:45:23

标签: javascript jquery backbone.js

我已将这个问题分解为可能的最小例子(即,它只是为了证明问题,而不是必然代表现实世界的情况)。

假设我有一个包含子视图的父视图(此处为“MainView”)(此处为“SubView”)。如果在任何时候,我需要重新渲染父视图(从而重新呈现子视图),我在子视图中丢失了事件绑定,尽管调用了delegateEvents

可以在这里找到一个jsfiddle:http://jsfiddle.net/ya87u/1/

以下是完整的代码:

var MainView = Backbone.View.extend({
    tagName : "div",
    initialize : function() {
        this.subView = new SubView();
    },
    render : function() {
        this.$el.html(this.subView.render().$el); // .html() breaks binds
        this.subView.delegateEvents(); // this re-establishes them
        return this;
    }
});

var SubView = Backbone.View.extend({
    tagName : "div",
    events : {
        "click .button1" : "onButtonPress"
    },
    onButtonPress : function() {
        alert("Button pressed");
    },
    render : function() {
        var html = "<button class='button1'>Button1</button>";
        this.$el.html(html);
        return this;
    }
});

var v = new MainView();
$("#area1").html(v.render().$el); // binds work fine

// do some work... then re-render...

$("#area1").html(v.render().$el); // breaks event binds

我不明白为什么会这样。任何意见都将不胜感激。

1 个答案:

答案 0 :(得分:4)

要保留绑定,您可以做三件事。

使用$ .append而不是$ .html

使用$.append将保持您的绑定完好无损,并注意不要丢失任何兄弟内容。

只需重新渲染而无需重新附加

在您的代码中,您重新渲染视图并重新附加其内容。这不是必需的。只需调用v.render()即可获得相同的视觉效果,但保持绑定完整。

var v = new MainView();
$("#area1").html(v.render().$el); // binds work fine

// do some work... then re-render…

v.render(); // keeps event binds

$("#area1").append(v.render().$el); // works too

在调用$ .html()

之前使用$ .empty()

根据jQuery documentation for $.html(htmlString)

  

如果要保持对这些DOM元素的引用并且需要它们保持不变,请使用.empty()。html(string)而不是.html(string),以便在新字符串出现之前从文档中删除元素。分配给元素。

重要的一点是$ .html需要一个html字符串,而不是元素,并且还取消绑定子节点上存在的任何事件处理程序。我可以解释这种行为的唯一方法是,不知何故,通过将dom树转换为字符串,反之亦然,事件将被删除。有趣的是,使用文档中提到的$ .empty()可以解决问题。

// any $.html reference needs to have an $.empty too
this.$el.empty().html(this.subView.render().$el);

// and then later for your mainView
$("#area1").empty().html(v.render().$el);