Sort a list with spans within, jQuery
I have a problem trying to sort a list with spans within.
Example:
<a href="">Sort by name</a>
<a href="">Sort by year</a>
<a href="">Sort by fruit</a>
<ul>
<li>
<span class="name">Carl</span>
<span class="year">1954</span>
<span class="fruit">Apple</span>
</li>
<li>
<span class="name">Ann</span>
<span class="year">1932</span>
<span class="fruit">Banana</span>
</li>
<li>
<span class="name">Joe</span>
<span 开发者_如何学运维class="year">1961</span>
<span class="fruit">Pineapple</span>
</li>
</ul>
So i want to able to sort by these three "categories". Anyone got a suggestion?
If we change your markup slightly to handle the links better, like this:
<div id="sort">
<a href="#name">Sort by name</a>
<a href="#year">Sort by year</a>
<a href="#fruit">Sort by fruit</a>
</div>
<ul id="things">
You could do a simple toggle 2-way sort like this:
$("#sort a").click(function(e) {
var desc = $(this).hasClass("asc"),
sort = this.hash.substr(1),
list = $("#things");
list.append(list.children().get().sort(function(a, b) {
var aProp = $(a).find("span."+sort).text(),
bProp = $(b).find("span."+sort).text();
return (aProp > bProp ? 1 : aProp < bProp ? -1 : 0) * (desc ? -1 : 1);
}));
$(this).toggleClass("desc", desc)
.toggleClass("asc", !desc)
.siblings().removeClass("asc desc");
e.preventDefault();
});
You can test it out here, there are other approaches of course (and the above can be slimmed down further)...my main point here was to demonstrate with Array.sort()
you can make pretty quick work of this.
Here's a breakdown of what the above does:
- Take
#XXX
and getXXX
, that's the class we want to sort on (you could use adata-
attribute here) - Grab the list - keep a reference so we don't keep selecting it
- Take the children (the
<li>
s), use.get()
to get the raw array of DOM elements .sort()
that array by:- Take
a
andb
passed in, those are<li>
elements .find()
the<span>
we care to sort on in there- Take the
.text()
of that<span>
- Return the comparison of that text (reverse if it we're
desc
, reversing the sort)
- Take
.append()
the sorted elements back to thelist
- The last bit is just changing the sort styling, if it's already sorted ascending, change it to a
desc
class, otherwise make it anasc
class, and remove either class from any siblings.
If you have a very large number of elements, you'll want to take a different approach like the plugins posted in other answers...they parse the data on updates only and cache the result in objects, so there's less DOM traversal when sorting (which compared to everything else, is expensive).
As an example of how to improve the above (but less readable as an example) would be to select the <span>
elements initially, cutting down on selector and .text()
time, like this:
$("#sort a").click(function(e) {
var desc = $(this).hasClass("asc"),
sort = this.hash.substr(1),
list = $("#things");
$(list.children().detach().find("span."+sort).get().sort(function(a, b) {
var aProp = $.text([a]),
bProp = $.text([b]);
return (aProp > bProp ? 1 : aProp < bProp ? -1 : 0) * (desc ? -1 : 1);
})).parent().appendTo(list);
$(this).toggleClass("desc", desc)
.toggleClass("asc", !desc)
.siblings().removeClass("asc desc");
e.preventDefault();
});
You can test out that version here.
I would suggest to rearrange your data in a table (cause that is what it represents) and then use someting like the JQuery table sorter plugin
This might also help :jQuery Quicksand plugin
精彩评论