我有一个集合,其中包含应该在列表中访问的几个项目。
因此集合中的每个元素都有自己的视图元素,然后将其添加到 DOM 中的一个容器中。
我的问题是:如何将我在具有比较器函数的集合中实现的排序顺序应用于 DOM?第一次渲染很简单:您遍历集合并创建所有视图,然后以正确的顺序附加到容器元素。
但是,如果模型被更改并由集合重新排序怎么办?如果添加元素怎么办?我不想重新渲染所有元素,而是只更新/移动必要的 DOM 节点。
我有一个集合,其中包含应该在列表中访问的几个项目。
因此集合中的每个元素都有自己的视图元素,然后将其添加到 DOM 中的一个容器中。
我的问题是:如何将我在具有比较器函数的集合中实现的排序顺序应用于 DOM?第一次渲染很简单:您遍历集合并创建所有视图,然后以正确的顺序附加到容器元素。
但是,如果模型被更改并由集合重新排序怎么办?如果添加元素怎么办?我不想重新渲染所有元素,而是只更新/移动必要的 DOM 节点。
添加元素的路径相当简单,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);
}
});
感谢文森特提供了一个很棒的解决方案。但是,元素的移动存在问题,具体取决于重新索引的元素移动的方向。如果它向下移动,则新位置的索引与 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);
}
}
});