将backbone视图与集合一起排序

5
我有一个集合,其中包含多个应该以列表形式访问的项。
因此,集合中的每个元素都会获得自己的视图元素,然后添加到DOM中的一个容器中。
我的问题是: 如何使用比较函数将集合中实现的排序顺序应用于DOM? 第一次呈现很容易:您遍历整个集合并创建所有视图,然后按正确的顺序附加到容器元素中。
但是,如果模型发生更改并且通过集合进行重新排序怎么办?如果添加了元素怎么办?我不想重新渲染所有元素,而是只更新/移动必要的DOM节点。

集合提供了“添加”事件,当指定“比较器”时,模型将插入到正确的索引位置。你别无选择,只能重新排列/重绘整个集合(为了简单起见)。 - Deeptechtons
是的,我有。请看下面的答案。 - Christian Engel
2个回答

7

添加模型

向集合中添加元素的路径相对简单。当模型被添加到集合时,在选项中会获取到index。这个索引是基于排序的索引,如果您有一个简单的视图,就可以在特定索引处插入视图。

更改排序属性

这有点棘手,我没有现成的答案(我有时也会遇到这个问题),因为当您最初添加它时,集合不会自动重新排列其按模型进行排序的属性。

透过backbone文档看:

具有比较函数的集合如果稍后更改了模型属性,则不会自动重新排序,因此在更改可能影响顺序的模型属性后,您可能希望调用sort。

因此,如果您在集合上调用排序,它将触发重置事件,您可以挂钩它以触发整个列表的重新绘制。

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

因此,您从中学到的几件事情是:

  • 始终可以通过调用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 - Christian Engel
在处理完整的列表重新排序时,这仍然是首选吗? - jribeiro

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接