使用Backbone.js反向sorting
有了Backbone.js,我已经有了一个用比较函数设置的集合。 这是很好的sorting模型,但我想扭转顺序。 我怎样才能将模型按降序而不是升序sorting?
那么你可以从比较器中返回负值。 例如,如果我们以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'));
就个人而言,我对这里给出的任何解决scheme都不满意:
-
sortingtypes为非数字时,乘以-1解决scheme失败。 虽然有办法解决这个问题(例如通过调用
Date.getTime()
),但这些情况是特定的。 我想要一个通用的方法来颠倒任何types的方向,而不必担心被分类字段的具体types。 -
对于string解决scheme,一次构build一个string似乎是一个性能瓶颈,特别是在使用大型集合(或实际上,大型sorting字段string)
这是一个很好地适用于string,date和数字字段的解决scheme:
首先,声明一个比较器,它将会颠倒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; }; }
现在,如果你想扭转sorting的方向,我们需要做的是:
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'));
这个工作的原因是,如果sorting函数有两个参数, Backbone.Collection.sort
行为将不同。 在这种情况下,其行为与传入Array.sort
的比较器的行为相同。 该解决scheme通过将单参数sortBy函数适配到两个参数比较器中并反转结果。
Backbone.js的集合比较器依赖于Underscore.js方法_.sortBy。 sortBy被实现的方式最终以一种使得sortingstring变得困难的方式“包装”了javascript .sort()。 string的简单否定最终返回NaN并打破这种sorting。
如果你需要用string进行反向sorting,比如反向字母sorting,那么这是一个非常糟糕的做法:
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中原生对象types的问题,可以通过提取string否定器并将其添加为String.Prototype上的方法来使代码更清晰。 但是,如果您知道自己在做什么,那么您可能只需要这样做,因为在JavaScript中修改原生对象types可能会产生无法预料的后果。
我的解决scheme是sorting后的结果。
为了防止双渲染先沉默,然后触发“重置”。
collections.sort({silent:true}) collections.models = collections.models.reverse(); collections.trigger('reset', collections, {});
修改你的比较函数返回一些反向比例的值,而不是返回你当前的数据。 一些代码来自: 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来决定集合中每个模型的sorting顺序。 这不断更新和收集保持在比较正确的顺序。
有关Array.prototype.sort()的信息可以在这里find: 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上面使用上面的文章作为指导,我能够使用下面的代码保持我的集合以相反的顺序sorting,然后我们简单地按照当前的顺序将集合渲染到页面,并且我们可以使用标志(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; } },
比较器除了两个模型之外,对集合或模型的更改还有分区函数运行,并更改集合的顺序。
我用Numbers和Stringstesting了这个方法,它对我来说似乎是完美的。
我真的希望这个答案可以帮助,因为我已经多次努力解决这个问题,通常最终使用工作。
这可以通过重写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();
该解决scheme不依赖于字段types。
// 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; };
这是一个非常简单的解决scheme,对于那些只是想要翻转当前的订单。 如果你有一个表格的列可以在两个方向上sorting,这是非常有用的。
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; }
我有一个稍微不同的要求,因为我在一个表中显示我的模型,我希望能够通过任何列(模型属性)和升序或降序sorting。
为了使所有的案件都能正常工作(值可以是string,空string,date,数字),我们花费了大量的时间,但是我认为这很接近。
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); },
我只是否定sorting函数来完成模型数组。 另外,我还没有触发“sorting”事件,直到完成反向操作。
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对集合模型进行反向sorting的简单方法
var reverseCollection = _.sortBy(this.models, function(model) { return self.indexOf(model) * -1; });