开发者

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 get XXX, that's the class we want to sort on (you could use a data- 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 and b 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)
  • .append() the sorted elements back to the list
  • The last bit is just changing the sort styling, if it's already sorted ascending, change it to a desc class, otherwise make it an asc 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜