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

Ele*_*One 5 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
Run Code Online (Sandbox Code Playgroud)

我不明白为什么会这样.任何投入将不胜感激.

Tor*_*ter 4

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

\n\n

使用 $.append 而不是 $.html

\n\n

使用$.append将使您的绑定保持完整,并确保您不会丢失任何同级内容。

\n\n

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

\n\n

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

\n\n
var v = new MainView();\n$("#area1").html(v.render().$el); // binds work fine\n\n// do some work... then re-render\xe2\x80\xa6\n\nv.render(); // keeps event binds\n\n$("#area1").append(v.render().$el); // works too\n
Run Code Online (Sandbox Code Playgroud)\n\n

在调用 $.html() 之前使用 $.empty()

\n\n

根据$.html(htmlString) 的 jQuery 文档

\n\n
\n

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

\n
\n\n

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

\n\n
// any $.html reference needs to have an $.empty too\nthis.$el.empty().html(this.subView.render().$el);\n\n// and then later for your mainView\n$("#area1").empty().html(v.render().$el);\n
Run Code Online (Sandbox Code Playgroud)\n