5

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

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

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

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

4

2 回答 2

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);
    }
});
于 2012-05-17T17:10:15.080 回答
0

感谢文森特提供了一个很棒的解决方案。但是,元素的移动存在问题,具体取决于重新索引的元素移动的方向。如果它向下移动,则新位置的索引与 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);
        }
    }
});
于 2017-09-25T20:06:45.993 回答