多个属性的高效 Marionette 排序 CollectionView

Efficient Marionette sorted CollectionView for multiple attributes

我正在尝试找到一种方法来有效地显示按多个属性排序的 Marionette.CollectionView,而无需修改基础 Backbone collection.对于这个例子,我使用 'name' 和 'online' 属性,并希望我的 CollectionView 分两部分显示:

我有一个 Collection of Backbone.Models 并且想在我的网络应用程序中使用它。所以在我的 Collection 上设置排序功能对我来说并不合适。

我的示例代码如下:

var MyCollection = Backbone.Collection.extend({
  model:Backbone.Model
});

var myCollection = new MyCollection();

myCollection.set([
  { name : 'Freddy', online : true },
  { name : 'Zorro', online : false },
  { name : 'Charlie', online : false },
  { name : 'Alice', online : true }
]);

var MyView = ... 
/* 
 omitted for brevity, though my template is like
 <li>{{name}} {{#if online}}(Online){{/if}}</li>
*/

var MyCollectionView = Marionette.Collection.extend({
  childView:MyView,
  viewComparator: function (item1, item2) {

    var item1Online = item1.get('online');
    var item2Online = item2.get('online');
    if (item1Online != item2Online)
      return item1Online ? -1 : 1;

    var item1Name = item1.get('name');
    var item2Name = item2.get('name');
    return item1Name.localeCompare(item2Name);
  }
});

var myCollectionView = new MyCollectionView({collection:myCollection});

appView.getRegion('example').show(myCollectionView);

我希望它显示为:

当所有数据一次添加到 collection 或 add/remove 事件时,这很好,但是如果在 [=] 中已经存在的模型上更新其中一个属性65=],视图不更新。


如果查理的 'online' 属性 更改为 true - 例如通过执行。

charlieModel.set('online', true)

我希望 CollectionView 自动呈现为:

有什么建议吗?非常感谢。

来自backbone documentation

Collections with a comparator will not automatically re-sort if you later change model attributes, so you may wish to call sort after changing model attributes that would affect the order.

您可以在代码中方便的地方放置一个侦听器,以侦听您所针对的模型属性的变化,这将触发对您的集合进行重新排序。

// for example in your collection
initialize: function() {
    this.on('change:name', function() { this.sort() }, this);
}

Marionette 团队建议在幕后有一个单独的 Backbone 集合,而不是在 CollectionView 上使用 viewComparator

CollectionView 上使用 reorderOnSort 在渲染速度方面产生了巨大的差异(至少加速了 10 倍)。

This option is useful when you have performance issues when you resort your CollectionView. Without this option, your CollectionView will be completely re-rendered, which can be costly if you have a large number of elements or if your ChildViews are complex. If this option is activated, when you sort your Collection, there will be no re-rendering, only the DOM nodes will be reordered.

我的最终示例代码:

  var MyView = Backbone.Marionette.ItemView.extend({
    modelEvents:{
     'change:name change:online': 'render'
    },
    template:template
  });

  var MyCollection = Backbone.Collection.extend({
    initialize : function(){
      this.on('change:name change:online', this.sort, this);
    },
    comparator : function(item1, item2){
      var item1online = item1.get('online');
      var item2online = item2.get('online');
      if (item1online != item2online)
        return item1online ? -1 : 1;

      return item1.get('name').localeCompare(item2.get('name'));
    }
  });

  var myCollection = new MyCollection();

  var MyCollectionView = Marionette.CollectionView.extend({
    childView : MyView,
    reorderOnSort : true
  });  

  var myCollectionView = new MyCollectionView({
    collection : myCollection
  });

  appView.region('example').show(myCollectionView);