使用 Backbone.js,我设置了一个带有比较器功能的集合。它很好地对模型进行了排序,但我想颠倒顺序。
如何按降序而不是升序对模型进行排序?
好吧,您可以从比较器返回负值。例如,如果我们以 Backbone 网站中的示例为例,并希望颠倒顺序,它将如下所示:
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
chapters.comparator = function(chapter) {
return -chapter.get("page"); // Note the minus!
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
alert(chapters.pluck('title'));
就个人而言,我对这里给出的任何解决方案都不满意:
当排序类型为非数字时,乘以 -1 解决方案无法工作。尽管有一些方法可以解决这个问题(例如通过调用 Date.getTime()),但这些情况是特定的。我想要一种通用的方法来反转任何排序的方向,而不必担心被排序的字段的特定类型。
对于字符串解决方案,一次构造一个字符的字符串似乎是性能瓶颈,尤其是在使用大型集合(或者实际上是大型排序字段字符串)时
这是一个适用于字符串、日期和数字字段的解决方案:
首先,声明一个比较器,它将反转 sortBy 函数的结果,如下所示:
function reverseSortBy(sortByFunction) {
return function(left, right) {
var l = sortByFunction(left);
var r = sortByFunction(right);
if (l === void 0) return -1;
if (r === void 0) return 1;
return l < r ? 1 : l > r ? -1 : 0;
};
}
现在,如果你想反转排序的方向,我们需要做的就是:
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
// Your normal sortBy function
chapters.comparator = function(chapter) {
return chapter.get("title");
};
// If you want to reverse the direction of the sort, apply
// the reverseSortBy function.
// Assuming the reverse flag is kept in a boolean var called reverseDirection
if(reverseDirection) {
chapters.comparator = reverseSortBy(chapters.comparator);
}
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
alert(chapters.pluck('title'));
这样做的原因是如果排序函数有两个参数,Backbone.Collection.sort
的行为会有所不同。在这种情况下,它的行为方式与传入 Array.sort
的比较器相同。该解决方案通过将单参数 sortBy 函数调整为两个参数比较器并反转结果来工作。
Backbone.js 的集合比较器依赖于 Underscore.js 方法 _.sortBy。 sortBy 的实现方式最终以一种使反向排序字符串变得困难的方式“包装”了 javascript .sort()。字符串的简单否定最终返回 NaN 并破坏排序。
如果您需要使用字符串执行反向排序,例如反向字母排序,这是一种非常hackish的方法:
comparator: function (Model) {
var str = Model.get("name");
str = str.toLowerCase();
str = str.split("");
str = _.map(str, function(letter) {
return String.fromCharCode(-(letter.charCodeAt(0)));
});
return str;
}
它绝不是漂亮的,但它是一个“字符串否定器”。如果您对在 javascript 中修改本机对象类型没有任何疑虑,您可以通过提取字符串否定符并将其添加为 String.Prototype 上的方法来使您的代码更清晰。但是,如果您知道自己在做什么,您可能只想这样做,因为在 javascript 中修改本机对象类型可能会产生无法预料的后果。
我的解决方案是在排序后反转结果。
为防止双重渲染,首先使用静默排序,然后触发“重置”。
collections.sort({silent:true})
collections.models = collections.models.reverse();
collections.trigger('reset', collections, {});
-Date.getTime()
,如果您认为系统中的日期将跨越 unix 纪元,则可能需要进行一些额外的黑客攻击。对于字母顺序,请查看上面安德鲁的答案。
修改您的比较器函数以返回一些反向比例值,而不是返回您当前的数据。一些代码来自:http://documentcloud.github.com/backbone/#Collection-comparator
例子:
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
/* Method 1: This sorts by page number */
chapters.comparator = function(chapter) {
return chapter.get("page");
};
/* Method 2: This sorts by page number in reverse */
chapters.comparator = function(chapter) {
return -chapter.get("page");
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
以下对我来说效果很好:
comparator: function(a, b) {
// Optional call if you want case insensitive
name1 = a.get('name').toLowerCase();
name2 = b.get('name').toLowerCase();
if name1 < name2
ret = -1;
else if name1 > name2
ret = 1;
else
ret = 0;
if this.sort_dir === "desc"
ret = -ret
return ret;
}
collection.sort_dir = "asc";
collection.sort(); // returns collection in ascending order
collection.sort_dir = "desc";
collection.sort(); // returns collection in descending order
我读到了一些 Backbone 比较器函数使用或模仿 JavaScript Array.prototype.sort() 函数的地方。这意味着它使用 1、-1 或 0 来决定集合中每个模型的排序顺序。这会不断更新,并且集合会根据比较器保持正确的顺序。
可以在此处找到有关 Array.prototype.sort() 的信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2Fsort
这个问题的许多答案只是在将其呈现到页面之前将顺序颠倒过来。这并不理想。
使用上面关于 Mozilla 的文章作为指南,我能够使用以下代码保持我的集合以相反的顺序排序,然后我们只需将集合以当前顺序呈现到页面,我们可以使用一个标志 (reverseSortDirection) 来反转顺序.
//Assuming this or similar will be in your Backbone.Collection.
sortKey: 'id', //The field name of the item in your collection
reverseSortDirection: false,
comparator: function(a, b) {
var sampleDataA = a.get(this.sortKey),
sampleDataB = b.get(this.sortKey);
if (this.reverseSortDirection) {
if (sampleDataA > sampleDataB) { return -1; }
if (sampleDataB > sampleDataA) { return 1; }
return 0;
} else {
if (sampleDataA < sampleDataB) { return -1; }
if (sampleDataB < sampleDataA) { return 1; }
return 0;
}
},
Comparator except 的两个模型,在对集合或模型进行更改时,compartor 函数运行并更改集合的顺序。
我已经用数字和字符串测试了这种方法,它似乎对我来说非常有效。
我真的希望这个答案能有所帮助,因为我已经多次解决这个问题并且通常最终会使用解决方法。
sortKey
和 reverseSortDirection
并从任何具有集合句柄的视图调用 .sort()
。对我来说,比其他投票率更高的答案更简单。
这可以通过重写 sortBy 方法来优雅地完成。这是一个例子
var SortedCollection = Backbone.Collection.extend({
initialize: function () {
// Default sort field and direction
this.sortField = "name";
this.sortDirection = "ASC";
},
setSortField: function (field, direction) {
this.sortField = field;
this.sortDirection = direction;
},
comparator: function (m) {
return m.get(this.sortField);
},
// Overriding sortBy (copied from underscore and just swapping left and right for reverse sort)
sortBy: function (iterator, context) {
var obj = this.models,
direction = this.sortDirection;
return _.pluck(_.map(obj, function (value, index, list) {
return {
value: value,
index: index,
criteria: iterator.call(context, value, index, list)
};
}).sort(function (left, right) {
// swap a and b for reverse sort
var a = direction === "ASC" ? left.criteria : right.criteria,
b = direction === "ASC" ? right.criteria : left.criteria;
if (a !== b) {
if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1;
}
return left.index < right.index ? -1 : 1;
}), 'value');
}
});
所以你可以像这样使用它:
var collection = new SortedCollection([
{ name: "Ida", age: 26 },
{ name: "Tim", age: 5 },
{ name: "Rob", age: 55 }
]);
//sort by "age" asc
collection.setSortField("age", "ASC");
collection.sort();
//sort by "age" desc
collection.setSortField("age", "DESC");
collection.sort();
此解决方案不依赖于字段类型。
// For numbers, dates, and other number-like things
var things = new Backbone.Collection;
things.comparator = function (a, b) { return b - a };
// For strings
things.comparator = function (a, b) {
if (a === b) return 0;
return a < b ? -1 : 1;
};
对于那些只想翻转当前订单的人来说,这是一个非常简单的解决方案。如果您有一个可以在两个方向上对列进行排序的表,这将很有用。
collection.models = collection.models.reverse()
如果您对桌案 (coffeescript) 感兴趣,可以将其与类似的东西结合使用:
collection.comparator = (model) ->
model.get(sortByType)
collection.sort()
if reverseOrder
collection.models = collection.models.reverse()
对于 id 的逆序:
comparator: function(object) { return (this.length - object.id) + 1; }
我有一个稍微不同的要求,因为我在表格中显示我的模型,并且我希望能够按任何列(模型属性)以及升序或降序对它们进行排序。
为了让所有案例都能正常工作(其中值可以是字符串、空字符串、日期、数字),我们花了相当多的时间。但是我认为这非常接近。
inverseString: function(str)
{
return str.split("").map(function (letter) { return String.fromCharCode(-(letter.charCodeAt(0))); }).join("");
}
getComparisonValue: function (val, desc)
{
var v = 0;
// Is a string
if (typeof val === "string")
{
// Is an empty string, upgrade to a space to avoid strange ordering
if(val.length === 0)
{
val = " ";
return desc ? this.inverseString(val) : val;
}
// Is a (string) representing a number
v = Number(val);
if (!isNaN(v))
{
return desc ? -1 * v : v;
}
// Is a (string) representing a date
v = Date.parse(val);
if (!isNaN(v))
{
return desc ? -1 * v : v;
}
// Is just a string
return desc ? this.inverseString(val) : val;
}
// Not a string
else
{
return desc ? -1 * val : val;
}
},
利用:
comparator: function (item)
{
// Store the collumn to 'sortby' in my global model
var property = app.collections.global.get("sortby");
// Store the direction of the sorting also in the global model
var desc = app.collections.global.get("direction") === "DESC";
// perform a comparison based on property & direction
return this.getComparisonValue(item.get(property), desc);
},
我只是覆盖了排序函数以在完成后反转模型数组。我也推迟了触发“排序”事件,直到反向完成之后。
sort : function(options){
options = options || {};
Backbone.Collection.prototype.sort.call(this, {silent:true});
this.models.reverse();
if (!options.silent){
this.trigger('sort', this, options);
}
return this;
},
最近遇到了这个问题,只是决定添加一个 rsort 方法。
Collection = Backbone.Collection.extend({
comparator:function(a, b){
return a>b;
},
rsort:function(){
var comparator = this.comparator;
this.comparator = function(){
return -comparator.apply(this, arguments);
}
this.sort();
this.comparator = comparator;
}
});
希望有人会发现这很有用
这是使用 UnderscoreJS 对集合模型进行反向排序的快速简便方法
var reverseCollection = _.sortBy(this.models, function(model) { return self.indexOf(model) * -1; });
不定期副业成功案例分享