关于javascript:将项目插入lobb.js集合中

Inserting an item into a backbone.js collection

是否有一种简单的方法将新模型项插入ribs.js Collection的中间,然后更新集合的View以将新项包含在正确的位置?

我正在控制从列表中添加/删除项目的控件。每个列表项都有自己的ModelView,对于整个集合,我也有一个View

每个项目视图都有一个Duplicate按钮,可克隆该项目的模型并将其插入到被单击的项目下方的索引位置的集合中。

将项目插入集合很简单,但是我很难弄清楚如何更新集合视图。我一直在尝试这样的事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ListView = Backbone.View.extend({
    el: '#list-rows',
    initialize: function () {
      _.bindAll(this);
      this.collection = new Items();
      this.collection.bind('add', this.addItem);
      this.render();
    },
    render: function () {
      this.collection.each(this.addItems);
      return this;
    },
    addItem: function (item) {
      var itemView = new ItemView({ model: item }),
          rendered = itemView.render().el,
          index = this.collection.indexOf(item),
          rows = $('.item-row');

      if (rows.length > 1) {
        $(rows[index - 1]).after(rendered);
      } else {
        this.$el.append(rendered);
      }
    }
}

此实现可以正常工作,但是在添加新项目时出现了奇怪的错误。我确定我可以解决这些问题,但是...

我的脑海中不断有声音告诉我,有一种更好的方法可以做到这一点。必须手动弄清楚在何处插入新的ItemView似乎真的很棘手-集合视图不应该知道如何重新呈现集合吗?

有什么建议吗?


我不认为添加新元素时重新渲染整个集合是最好的解决方案。这比在正确位置插入新项目要慢,尤其是在列表很长的情况下。

此外,请考虑以下情形。您在集合中加载了一些项目,然后添加了n更多项目(例如,用户单击"加载更多"按钮)。为此,您可以调用fetch()方法,将add: true作为选项之一。当从服务器接收回数据时,将触发事件n次,最终您将重新呈现列表n次。

我实际上在使用您问题中的代码变体,这是我对'add'事件的回调:

1
2
3
4
5
6
7
8
9
var view, prev, prev_index;
view = new ItemView({ model: new_item }).render().el;
prev_index = self.model.indexOf(new_item) - 1;
prev = self.$el.find('li:eq(' + prev_index + ')');
if (prev.length > 0) {
    prev.after(view);
} else {
    self.$el.prepend(view);
}

因此,从本质上讲,我只是在使用:eq() jQuery选择器,而不是像您那样获取所有元素,因此应该使用更少的内存。


我通常的做法是让ListView渲染其render函数中的每个ItemView。然后,我将add事件绑定到render函数,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ListView = Backbone.View.extend({
  el: '#list-rows'
  , initialize: function () {
    _.bindAll(this);
    this.collection = new Items();
    this.collection.bind('add', this.render);
    this.render();
  }
  , render: function () {
    this.$el.empty();
    var self = this;
    this.collection.each(function(item) {
      self.$el.append(new ItemView({ model: item }).render().el);
    });
    return this;
  }
}

每次调用this.collection.add(someModel, {at: index})时,视图都会相应地重新呈现。