如何使用jQuery按字母顺序对列表进行排序?

231 javascript sorting jquery dom

我有点超出我的深度,我希望这实际上是可能的.

我希望能够调用一个按字母顺序对列表中所有项目进行排序的函数.

我一直在浏览jQuery UI进行排序,但似乎不是这样.有什么想法吗?

Sol*_*ogi 326

像这样的东西:

var mylist = $('#myUL');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
   return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase());
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });
Run Code Online (Sandbox Code Playgroud)

从此页面:http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/

上面的代码将使用id"myUL"对无序列表进行排序.

或者你可以使用像TinySort这样的插件.https://github.com/Sjeiti/TinySort

  • HL Menken的引言描述了这个解决方案:"对于每个问题,都有一个简单,优雅和错误的解决方案." 此过程在O(n ^ 2)时间内运行.相对较短的列表并不明显,但在包含100多个元素的列表中,完成排序需要3-4秒. (26认同)
  • 有些东西可以优雅而且耐人寻味,但仍然失败.优雅并不意味着成功. (18认同)
  • 这个解决方案没错.它回答了这个问题.OP未指明他需要对超过100个项目的列表进行排序.如果他的列表永远不会超过100个项目,这个解决方案是完全可以接受的.+1表示解决方案很慢,-1表示满足要求的解决方案为'错误'. (13认同)
  • 可以用$(listitems)替换最后一行.appendTo(mylist); ? (6认同)
  • @Nathan:关于"对于每一个问题,都有一个简单,优雅,错误的解决方案." - 好吧,错误的解决方案并不优雅. (5认同)
  • 这对我有用,但我确实添加了`trim()`来处理空白.`return $(a).text().toUpperCase().trim().localeCompare($(b).text().toUpperCase().trim())` (2认同)
  • @NathanStrong:哪个进程在 O(n^2) 时间内运行? (2认同)

Jos*_*ola 105

不会需要jQuery来做到这一点...

function sortUnorderedList(ul, sortDescending) {
  if(typeof ul == "string")
    ul = document.getElementById(ul);

  // Idiot-proof, remove if you want
  if(!ul) {
    alert("The UL object is null!");
    return;
  }

  // Get the list items and setup an array for sorting
  var lis = ul.getElementsByTagName("LI");
  var vals = [];

  // Populate the array
  for(var i = 0, l = lis.length; i < l; i++)
    vals.push(lis[i].innerHTML);

  // Sort it
  vals.sort();

  // Sometimes you gotta DESC
  if(sortDescending)
    vals.reverse();

  // Change the list on the page
  for(var i = 0, l = lis.length; i < l; i++)
    lis[i].innerHTML = vals[i];
}
Run Code Online (Sandbox Code Playgroud)

使用方便...

sortUnorderedList("ID_OF_LIST");
Run Code Online (Sandbox Code Playgroud)

现场演示→

  • 我在这种方法中发现的一个问题是,由于它只是被移动的文本,如果在排序之前使用jQuery.data将数据与DOM节点相关联,那么这些关联现在指向排序后的错误节点. (28认同)
  • 恕我直言,这是一个可怕的答案.完全可以重新排列DOM节点,而无需将它们序列化并再次对它们进行反序列化,并且不会破坏任何附加的属性和/或事件. (13认同)
  • 使用innerHTML移动元素是一个糟糕的解决方案,因为它们在排序后不是相同的元素.所有对元素的现有引用都将丢失.从JavaScript绑定的所有事件侦听器都将丢失.最好存储元素而不是innerHTML,使用sort函数(vals.sort(function(a,b){return b.innerHTML <a.innerHTML;}))和appendChild来移动元素. (12认同)
  • Buhuuu innerHTML!不要使用它.这是微软专有的东西,W3C从未承认过. (3认同)
  • ...但是如果你要使用jQuery,你会怎么做? (3认同)

Jee*_*han 93

$(".list li").sort(asc_sort).appendTo('.list');
//$("#debug").text("Output:");
// accending sort
function asc_sort(a, b){
    return ($(b).text()) < ($(a).text()) ? 1 : -1;    
}

// decending sort
function dec_sort(a, b){
    return ($(b).text()) > ($(a).text()) ? 1 : -1;    
}
Run Code Online (Sandbox Code Playgroud)

现场演示:http://jsbin.com/eculis/876/edit

  • 这是最好的答案.我甚至喜欢这样一行:`$(".list li").sort(function(a,b){return($(b).text())<($(a).text( ));})appendTo( '列表');`.但有一句话:`.text()`应该是`.text().toUpperCase()` (15认同)
  • 小心选择器!".list li"将选择所有后代LI标签,而不仅仅是直接的孩子. (8认同)
  • @DougDomeny是正确的。如果可能的话,最好调用`$(“。list”)。children()`,或将选择器设置为具有直接子关系的选择器,例如`$(“。list&gt; li”)`。 (3认同)

小智 38

要使此工作适用于所有浏览器(包括Chrome),您需要使sort()的回调函数返回-1,0或1.

http://inderpreetsingh.com/2010/12/01/chromes-javascript-sort-array-function-is-different-yet-proper/

function sortUL(selector) {
    $(selector).children("li").sort(function(a, b) {
        var upA = $(a).text().toUpperCase();
        var upB = $(b).text().toUpperCase();
        return (upA < upB) ? -1 : (upA > upB) ? 1 : 0;
    }).appendTo(selector);
}
sortUL("ul.mylist");
Run Code Online (Sandbox Code Playgroud)

  • @bowserm,appendTo方法移动DOM元素而不是复制它们. (3认同)
  • 在追加排序的li元素之前,不应该从ul.myList中删除所有li元素吗? (2认同)
  • @Daud,不需要显式删除LI元素. (2认同)

Sal*_*n A 29

如果你使用的是jQuery,你可以这样做:

$(function() {

  var $list = $("#list");

  $list.children().detach().sort(function(a, b) {
    return $(a).text().localeCompare($(b).text());
  }).appendTo($list);

});
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<ul id="list">
  <li>delta</li>
  <li>cat</li>
  <li>alpha</li>
  <li>cat</li>
  <li>beta</li>
  <li>gamma</li>
  <li>gamma</li>
  <li>alpha</li>
  <li>cat</li>
  <li>delta</li>
  <li>bat</li>
  <li>cat</li>
</ul>
Run Code Online (Sandbox Code Playgroud)

请注意,从比较函数返回1和-1(或0和1)是绝对错误的.


Buz*_*zut 7

@ SolutionYogi的答案就像魅力一样,但似乎使用$ .each比直接附加listitems更简单有效:

var mylist = $('#list');
var listitems = mylist.children('li').get();

listitems.sort(function(a, b) {
   return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase());
})

mylist.empty().append(listitems);
Run Code Online (Sandbox Code Playgroud)

小提琴


ori*_*dam 6

improvement based on Jeetendra Chauhan's answer

$('ul.menu').each(function(){
    $(this).children('li').sort((a,b)=>a.innerText.localeCompare(b.innerText)).appendTo(this);
});
Run Code Online (Sandbox Code Playgroud)

why i consider it an improvement:

  1. using each to support running on more than one ul

  2. using children('li') instead of ('ul li') is important because we only want to process direct children and not descendants

  3. using the arrow function (a,b)=> just looks better (IE not supported)

  4. using vanilla innerText instead of $(a).text() for speed improvement

  5. using vanilla localeCompare improves speed in case of equal elements (rare in real life usage)

  6. using appendTo(this) instead of using another selector will make sure that even if the selector catches more than one ul still nothing breaks