2

我修改了我的 Backbone 应用程序以使用 DOM 文档片段呈现一个大表,当有很多行时,这会带来很好的性能改进。

不幸的是,这似乎破坏了事件处理,因此每一行的视图不再接收点击事件。我创建了一个最小的示例来演示这一点。

我该怎么做才能解决这个问题?

// Javascript
$(window).load(function(){

  var Item = Backbone.Model.extend();

  var Items = Backbone.Collection.extend({
      model: Item,
      count: 5,
      initialize: function() {
        for(i=0; i<this.count; i++){
          this.add(new Item({text: i}));
        }
      }
  });

  var ItemView = Backbone.View.extend({
      tagName: 'tr',

      initialize: function(item) {
        this.item = item;
      },

      render: function() {
        this.$el.append('<td class="item">' + this.item.get('text') + '</td>');
        return this;
      },

      events: function() {
        return { "click .item": function() {
            console.log('handling click on item '+this.item.get('text'));
          }
        };
      }

  });

  var TableBodyView = Backbone.View.extend({
      tagName: 'tbody',

      render: function() {
          if(this.options.useFragment){
              this.renderWithFragment();
          } else {
               this.renderWithoutFragment();
          }
        return this;
      },

      renderWithFragment: function() {
          var fragment = document.createDocumentFragment();
          this.collection.each(function(item){
            fragment.appendChild((new ItemView(item)).render().el);
          });
          this.$el.append(fragment.cloneNode(true));
      },

      renderWithoutFragment: function() {
          self = this;
          this.collection.each(function(item){
              self.$el.append((new ItemView(item)).render().el);
          });
      }
  });

var items = new Items();
$('#t1').append((new TableBodyView({collection: items, useFragment: false})).render().el);
$('#t2').append((new TableBodyView({collection: items, useFragment: true})).render().el);
});

// HTML
<table id="t1" />
<table id="t2" />

// CSS
table { float: left; margin: 10px; padding: 5px; }
table#t1 { background: green; }
table#t2 { background: red; }
4

1 回答 1

4

您的问题是cloneNode明确不复制事件处理程序:

克隆节点会复制其所有属性及其值,但不会复制事件侦听器。

所以,当你这样做时:

this.$el.append(fragment.cloneNode(true));
// No more events -------^ 

delegate您失去了附加到视图的Backbone ,el并且您的所有事件处理都消失了。如果要克隆el并保留事件,则可以将withDataAndEvents标志与 jQuery 一起使用clone

.clone( [withDataAndEvents] [, deepWithDataAndEvents] )

withDataAndEvents一个布尔值,指示是否应将事件处理程序和数据与元素一起复制。默认值为false

deepWithDataAndEvents一个布尔值,指示是否应复制克隆元素的所有子元素的事件处理程序和数据。默认情况下,它的值匹配第一个参数的值(默认为false)。

所以你应该可以这样做:

this.$el.append($(fragment).clone(true));

演示(请打开您的控制台):http: //jsfiddle.net/ambiguous/M6SvH/

于 2012-11-18T00:06:44.417 回答