将骨干视图与集合一起订购

时间:2012-05-17 16:40:20

标签: sorting backbone.js collections view

我有一个集合,其中包含几个应该可以在列表中访问的项目。

因此集合中的每个元素都会获得自己的视图元素,然后将其添加到DOM中的一个容器中。

我的问题是: 如何将使用比较器函数在集合中实现的排序顺序应用于DOM? 第一个渲染很简单:您遍历集合并创建所有视图,然后以正确的顺序将其附加到容器元素。

但是,如果模型被更改并被集合重新排序,该怎么办?如果添加了元素怎么办?我不想重新渲染所有元素,而只是更新/移动必要的DOM节点。

2 个答案:

答案 0 :(得分:7)

模型添加

添加元素的路径非常简单,因为当模型添加到集合时,您可以在选项中获得index。此索引是排序索引,如果您有一个简单的视图,则应该很容易将视图插入某个索引。

排序属性更改

这个有点棘手,而且我没有一个方便的答案(我有时也在努力解决这个问题),因为在更改模型获得的属性后,集合不会自动重新调整其顺序按最初添加时排序。

来自骨干文档的

  

具有比较器功能的集合不会自动重新排序   如果您稍后更改模型属性,那么您可能希望调用sort   在更改会影响订单的模型属性之后。

因此,如果您对集合调用sort,它将触发reset事件,您可以将其挂钩以触发重绘整个列表。

在处理相当长且可能严重降低用户体验甚至导致挂起的列表时效率非常低

所以你可以从中得到的一些事情就是知道你可以:

  • 总是通过调用collection.indexOf(model)
  • 排序后找到模型的索引
  • add事件(第三个参数)
  • 获取模型的索引

编辑:

在考虑了一下之后我想出了类似的东西:

var Model = Backbone.Model.extend({
    initialize: function () {
        this.bind('change:name', this.onChangeName, this);
    },
    onChangeName: function ()
    {
        var index, newIndex;

        index = this.collection.indexOf(this);
        this.collection.sort({silent: true});
        newIndex = this.collection.indexOf(this);
        if (index !== newIndex)
        {
            this.trigger('reindex', newIndex);
            // or
            // this.collection.trigger('reindex', this, newIndex);

        }
    }
});

然后在你看来你可以听

var View = Backbone.View.extend({
    initialize: function () {
        this.model.bind('reindex', this.onReindex, this);
    },
    onReindex: function (newIndex)
    {
        // execute some code that puts the view in the right place ilke
        $("ul li").eq(newIndex).after(this.$el);
    }
});

答案 1 :(得分:0)

感谢Vincent提供了一个很棒的解决方案。然而,元素的移动存在问题,这取决于重新索引元素移动的方向。如果它向下移动,新位置的索引与DOM中的索引的索引不匹配。这解决了它:

var Model = Backbone.Model.extend({
    initialize: function () {
        this.bind('change:name', this.onChangeName, this);
    },
    onChangeName: function () {
        var fromIndex, toIndex;

        fromIndex = this.collection.indexOf(this);
        this.collection.sort({silent: true});
        toIndex = this.collection.indexOf(this);
        if (fromIndex !== toIndex)
        {
            this.trigger('reindex', fromIndex, toIndex);
            // or
            // this.collection.trigger('reindex', this, fromIndex, toIndex);
        }
    }
});

示例听力部分:

var View = Backbone.View.extend({
    initialize: function () {
        this.model.bind('reindex', this.onReindex, this);
    },
    onReindex: function (fromIndex, toIndex) {
        var $movingEl, $replacingEl;

        $movingEl = this.$el;
        $replacingEl = $("ul li").eq(newIndex);

        if (fromIndex < toIndex) {
            $replacingEl.after($movingEl);
        } else {
            $replacingEl.before($movingEl);
        }
    }
});