Efficient Marionette为多个属性排序CollectionView

时间:2015-08-17 22:47:29

标签: javascript backbone.js marionette

我正在尝试找到一种方法来有效地显示已排序的Marionette.CollectionView,按多个属性排序,而不修改底层的Backbone集合。对于此示例,我使用'name'和'online'属性,并希望我的CollectionView分为两部分显示:

  • 在线,按字母顺序
  • 离线,按字母顺序

我有一个Backbone.Model集合,并希望在我的Web应用程序中使用它。所以在我的Collection上使用sort函数对我来说感觉不对。

我的示例代码如下:

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);

我希望将其显示为:

  • Alice(在线)
  • Freddy(在线)
  • 查理
  • 佐罗

将所有数据一次添加到集合中,或者添加/删除事件但是如果在已经在集合中的模型上更新其中一个属性,则视图不会更新。

如果查理的“在线”属性改为真实 - 例如通过表演。

charlieModel.set('online', true)

我希望CollectionView自动呈现为:

  • Alice(在线)
  • 查理(在线)
  • Freddy(在线)
  • 佐罗

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

2 个答案:

答案 0 :(得分:1)

来自backbone documentation

  

如果稍后更改模型属性,使用比较器的集合将不会自动重新排序,因此您可能希望在更改会影响订单的模型属性后调用sort。

您可以在代码中的某个位置放置一个侦听器,以更改您的目标模型属性,从而触发对您的集合进行重新排序。

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

答案 1 :(得分:0)

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

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

  

当您使用CollectionView时遇到性能问题时,此选项很有用。   如果没有此选项,您的CollectionView将完全重新呈现,即可   如果您有大量元素或者您的ChildViews很复杂,则代价很高。如果这个选项   激活,当您对Collection进行排序时,将不会重新呈现,只有DOM节点   将被重新订购。

我的最终示例代码:

  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);