2

我可能在这里遗漏了一些微不足道的东西,但看起来 setElement 并没有重新绑定事件,尽管文档和代码都说应该这样做。

我试图用尽可能少的代码重新创建问题,但仍然很多,所以我将它发布在 Gist 上:

https://gist.github.com/gooli/baecc277d864e28eb2c7

当我单击其中一个复选框时,“已选择”会按原样打印在控制台上。但是当我再次单击它时,它没有,输入不再绑定到事件。

我这样做是因为我真的想让模板包含<tr>元素而不仅仅是内部<td>元素。

当我删除<tr>元素、tagName: 'tr'在视图中使用并使用通用this.$el.html(...)公式进行渲染时,一切正常。

我错过了什么?

4

2 回答 2

2

根据 jakee 的回答,我想出了一个更好的解决方案,它不需要重新实现内部的模板逻辑render

window.DayView = Backbone.View.extend({
    template: Handlebars.compile($('#day-template').html()),
    events: {
        'click .select input': 'select'
    },
    initialize: function () {
        this.model.bind('change', this.render, this);
        this.setElement(this.template(this.model.toJSON()));
    },
    render: function() {
        console.log('render');
        this.$el.html($(this.template(this.model.toJSON())).html());
        return this;
    },
    select: function (event) {
        console.log('selected');
        this.model.set({selected:$(event.target).is(':checked')});
    }
});

initialize方法使用整个模板来创建元素。该render方法仅使用模板的内部 html 来呈现新值。

这看起来很干净,允许我在模板中定义所有视图的 HTML,而无需依赖tagName. 我是一个快乐的露营者。

于 2013-06-17T13:52:23.263 回答
1

由于多种原因,您的方法存在问题。

this.model.each(function(day) {
  that.$el.append(new DayView({model:day}).render().$el);
});

DayView在这里,您将元素附加到DayListView. 您将每个视图的 附加$el到父视图的$el. 当子元素具有固定的包装元素时,这是标准的。这是您定义tagName属性的情况。但是当你不断地重新分配视图的元素时,这是有问题的。

  1. 您将 ItemView 元素添加到父级
  2. 你点击选择
  3. undelegateEvents为 ItemView 调用
  4. ItemView 的$elel填充了新模板
  5. delegateEvents为 ItemView 调用

现在导致您遇到的问题是:

  1. 旧的 ItemView 内容不会从父视图中删除
  2. 新的 ItemView 内容未添加到父视图
  3. 事件被委托给不在 DOM 中的元素

我对您的问题的解决方案是:

window.DayView = Backbone.View.extend({
  template: Handlebars.compile($('#day-template').html()),
  events: {
    'click .select input': 'select'
  },
  initialize: function () {
    this.model.bind('change', this.render, this);
    this.setElement(this.template(this.model.toJSON()));
  },
  render: function() {
    this.$el.find('.name').text(this.model.get('name'));
    this.$el.find('.select input').attr('checked', this.model.get('selected'));
    return this;
  },
  select: function (event) {
    this.model.set({selected:$(event.target).is(':checked')});
  }
});

这样您就不会在每次单击复选框时都替换视图的元素。现在这个解决方案很可能远非最佳,但应该指向正确的方向。

希望这可以帮助!

于 2013-06-17T12:58:55.180 回答