主干不触发事件

Backbone Not Firing Events

本文关键字:事件      更新时间:2023-09-26

这是我的应用在jsfiddle中的一个例子:http://jsfiddle.net/GWXpn/1/

问题是click事件根本没有被触发。我在控制台没有得到任何JS错误。

首先,我想显示一个无序列表,其中包含一对if项,每个项都应该是可点击的。我是这样做的:

var FooModel = Backbone.Model.extend({});
var ListView = Backbone.View.extend({
        tagName: 'ul', // name of (orphan) root tag in this.el
        initialize: function() {
            _.bindAll(this, 'render'); // every function that uses 'this' as the current object should be in here
        },
        render: function() {
            for (var i = 0; i < 5; i++) {
                var view = new SingleView({
                    model: new FooModel()
                });
                $(this.el).append(view.render().el);
            }
            return this; // for chainable calls, like .render().el
        }
    });
      var SingleView = Backbone.View.extend({
        tagName: 'li', // name of (orphan) root tag in this.el
        initialize: function() {
            _.bindAll(this, 'render', 'click'); // every function that uses 'this' as the current object should be in here
        },
        events: {
            "click": "click"
        },
        click: function(ev) {
            console.log("aaa");
            alert(333);
        },
        render: function() {
            $(this.el).append("aaa");
            return this; // for chainable calls, like .render().el
        }
    });

我想把我的应用分成多个模块(header, body, footer),所以我创建了一个抽象模型,并从中扩展了我的模块:

var AbstractModule = Backbone.Model.extend({
    getContent: function () {
        return "TODO";
    },
    render: function () {
        return $('<div></div>').append(this.getContent());
    }
});
var HeaderModule = AbstractModule.extend({
    id: "header-module",
});
var BodyModule = AbstractModule.extend({
    id: "body-module",
    getContent: function () {
        var listView = new ListView();
        return $("<div/>").append($(listView.render().el).clone()).html();
    }
});
var ModuleCollection = Backbone.Collection.extend({
    model: AbstractModule,
});

然后我创建了我的主视图并渲染了它所有的子视图:

var AppView = Backbone.View.extend({
    el: $('#hello'),
    initialize: function (modules) {
        this.moduleCollection = new ModuleCollection();
        for (var i = 0; i < modules.length; i++) {
            this.moduleCollection.add(new modules[i]);
        }
    },
    render: function () {
        var self = this;
        _(this.moduleCollection.models).each(function (module) { // in case collection is not empty
            $(self.el).append(module.render());
        }, this);
    }
});
var appView = new AppView([HeaderModule, BodyModule]);
appView.render();

知道为什么吗?

一行有两个bug:

return $("<div/>").append($(listView.render().el).clone()).html();

首先,clone不会复制事件,除非您明确要求它们:

通常,绑定到原始元素的任何事件处理程序都不会复制到克隆元素。可选的withDataAndEvents参数允许我们更改此行为,并将所有事件处理程序的副本绑定到元素的新副本。
[…]
从jQuery 1.5开始,withDataAndEvents可以选择性地增强deepWithDataAndEvents,以复制克隆元素的所有子元素的事件和数据。

你在这里克隆了<ul>,所以你要把这两个标志都设置为true

另外,html返回一个字符串,字符串没有事件,所以你在事件杀死上加倍下注。

我不明白你为什么要克隆任何东西,你应该返回el并完成它:

    return listView.render().el;

如果你坚持克隆,那么你会想要这样的东西:

    return $(listView.render().el).clone(true, true);

但那只是毫无意义的忙碌工作。

顺便说一句,'title''Title'是不同的模型属性,所以你会想说:
console.log(this.model.get("title") + " clicked");
不是

console.log(this.model.get("Title") + " clicked");

此外,主干集合有很多下划线方法混合在一起,所以不要直接与集合的models混淆,你目前说:

_(this.moduleCollection.models).each(...)

说:

this.moduleCollection.each(...)

正如Loamhoof提到的,0.3.3已经过时了,请升级到主干、下划线和jQuery的新版本。您还应该阅读更改日志,以便您可以使用较新的功能(例如this.$el代替$(this.el),减少_.bindAll调用,listenTo,…)。

部分修正的演示(包括更新的库):http://jsfiddle.net/ambiguous/e4Pba/

我还去掉了alert调用,这是一个令人讨厌的调试技术,如果您进入意外的无限循环,可能会导致巨大的混乱,console.log更友好。