Javascript 主干视图事件不会触发

Javascript 主干视图事件不会触发,javascript,jquery,backbone.js,backbone-views,backbone-events,Javascript,Jquery,Backbone.js,Backbone Views,Backbone Events,我有一个简单的主干视图,如下所示: /** * Renders a form view for an event object. */ APP.EventFormView = Backbone.View.extend({ tagName: 'form', events: { 'keydown': 'keyPressed', 'focus input': 'inputChanged', 'change select': 'sel

我有一个简单的主干视图,如下所示:

/**
 * Renders a form view for an event object.
 */
APP.EventFormView = Backbone.View.extend({
    tagName: 'form',

    events: {
        'keydown': 'keyPressed',
        'focus input': 'inputChanged',
        'change select': 'selectChanged',
        'change textarea': 'textareaChanged'
    },

    initialize: function() {
        this.template = _.template($('#newevent-form').html());
        this.listenTo(this.model, 'change', this.render);
        this.listenTo(APP.eventTypes, 'update', this.render);
        this.listenTo(APP.selectedEvent, 'update', this.render);
    },

    render: function() {
        var modelJSON = this.model.toJSON();
        if ('id' in modelJSON && modelJSON.id !== "") {
            this.loadForm();
        } else if (!('id' in modelJSON) || modelJSON.id === "") {
            this.loadForm();
        } else {
            this.$el.html('');
        }
        return this;
    },

    loadForm: function() {
        var templateData = $.extend(this.model.toJSON(),
            {"event_types":APP.eventTypes.toJSON()});
        this.$el.html('');
        this.$el.html(this.template($.extend(this.model.toJSON(),
                {event_types: APP.eventTypes.toJSON()})));
        $('.ev-main-container').html('').html(this.el);
    },

    inputChanged: function(e) {
        console.log('inputChanged');
    },

    selectChanged: function(e) {
        console.log('selectChanged');
    },

    textareaChanged: function(e) {
        console.log('textareaChanged');
    },

    keyPressed: function(e) {
        console.log('key pressed');
    }
});
我在document.ready下按如下方式初始化此视图:

// Initialize the form view
APP.selectedEvent = APP.selectedEvent || new APP.Event();
APP.eventFormView = new APP.EventFormView({model: APP.selectedEvent});
APP.eventFormView.render();
但我所定义的所有事件都不是出于某种原因触发的,我在这里做错了什么

更新: 好的,如果我删除
$('.ev main container').html(''.html)(this.el),我就失败了loadForm
方法中选择code>,并按如下方式初始化视图,它可以工作:

APP.eventFormView = new APP.EventFormView({
    model: APP.selectedEvent,
    el: $('.ev-main-container'),
});

我能够解决这个问题,但我仍然不明白为什么会发生这种情况,有谁能稍微解释一下发生了什么以及它是如何工作的。

jQuery的
html
函数有一个很多人似乎都忘记的副作用,从以下方面:

jQuery在用新内容替换子元素之前,会从子元素中删除其他构造(如数据和事件处理程序)

当你做这样的事情时,想想这意味着什么:

container.html(view.el);
container.html(view.el);
第一次调用
container.html()
。但第二个将在添加新内容之前“从子元素中删除…事件处理程序”(例如
view.el
)。因此,在第二次调用
container.html()
之后,
view.el
上的所有事件都消失了。听起来熟悉吗

在视图中有很多东西将调用
render
,而
render
最终将执行以下操作:

$('.ev-main-container').html('').html(this.el);
您的事件将在第二次调用时悄无声息地消失,但HTML看起来很好

考虑这个简化的例子():

你会明白你的问题所在

如果将视图的
el
设置为
.ev主容器
,则将使用
html()
更改
el
的内容,而不是更改包含
el
的元素的内容。一旦您完全在
el
中工作,您就不再意外地重复使用某个元素,也不再意外地从该元素中删除事件绑定

我预防主干网事件问题的经验法则:

  • 永远不要将视图附加到现有DOM节点,始终让视图创建并拥有自己的
    el
    ,并让调用方将该
    el
    放入容器中
  • 在视图上调用
    remove
    ,在不再需要视图时将其处理掉
  • 不要试图重复使用视图,需要时创建视图,不需要时删除视图
  • 没有视图引用其
    el
    之外的任何内容
  • 当然也有例外,这种方法不能解决所有问题,但它是一个很好的起点,可以避免大多数常见问题

    var V = Backbone.View.extend({
        tagName: 'form',
        events: {
            'click button': 'clicked'
        },
        initialize: function() {
            this.template = _.template($('#t').html());
        },
        render: function() {
            this.$el.html('');
            this.$el.html(this.template());
            $('.ev-main-container').html('').html(this.el);
            return this;
        },
        clicked: function() {
            console.log('clicked');
        }
    });
    var v = new V;
    v.render();
    $('#re-render').click(function() {
        v.render();
        console.log('Re-rendered');
    });