【问题标题】:Ordering backbone views together with collection将主干视图与集合一起排序
【发布时间】:2012-05-25 06:33:22
【问题描述】:

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

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

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

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

【问题讨论】:

  • Collection 提供 add 事件,当指定 comparator 时,模型会插入到正确的索引处。你别无选择,只能重排/重绘整个集合(为了简单起见)
  • 是的,我愿意。看看下面的答案。

标签: sorting backbone.js collections view


【解决方案1】:

模型添加

添加元素的路径相当简单,当模型添加到集合时,您会在选项中获得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);
    }
});

【讨论】:

  • 是的,添加很容易 - 度假村是难题。对于主干方面,我有类似的想法,但是硬的东西是你只留下评论的地方。 “一些将视图放在正确位置的代码”:D
  • 在处理完整列表时,这是否更可取?
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    • 1970-01-01
    相关资源
    最近更新 更多