ฉันจะเรียงลำดับรายการตามตัวอักษรโดยใช้ jQuery ได้อย่างไร


233

ฉันค่อนข้างลึกที่นี่และฉันหวังว่ามันจะเป็นไปได้จริง

ฉันต้องการที่จะสามารถเรียกฟังก์ชั่นที่จะเรียงลำดับรายการทั้งหมดในรายการของฉันตามลำดับตัวอักษร

ฉันดู jQuery UI สำหรับการเรียงลำดับ แต่ดูเหมือนจะไม่เป็นเช่นนั้น ความคิดใด ๆ



ตรวจสอบUnderscore.jsหรือSugar.js
กริช Khaira

คำตอบ:


106

คุณไม่จำเป็นต้อง 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];
}

ง่ายต่อการใช้...

sortUnorderedList("ID_OF_LIST");

การสาธิตสด→


29
ปัญหาหนึ่งที่ฉันค้นพบด้วยวิธีนี้คือเนื่องจากมีเพียงข้อความที่ถูกย้ายไปหากคุณเชื่อมโยงข้อมูลไปยังโหนด DOM โดยใช้ jQuery.data ก่อนการเรียงลำดับการเชื่อมโยงเหล่านั้นจะชี้ไปยังโหนดที่ไม่ถูกต้องหลังจากเรียงลำดับ
Rudism

13
อิลิเมนต์การย้ายที่มี innerHTML เป็นวิธีแก้ปัญหาที่ไม่ดีเพราะมันไม่ได้เป็นอิลิเมนต์เดียวกันหลังจากเรียงลำดับ การอ้างอิงองค์ประกอบที่มีอยู่ทั้งหมดหายไป ตัวรับฟังเหตุการณ์ทั้งหมดที่ผูกไว้จาก JavaScript จะหายไป มันจะเป็นการดีกว่าถ้าจะเก็บองค์ประกอบแทน innerHTML ใช้ฟังก์ชั่น sort (vals.sort (ฟังก์ชั่น (a, b)) {return b.innerHTML <a.innerHTML;})) และ appendChild เพื่อย้ายองค์ประกอบ
gregers

3
Buhuuu innerHTML! อย่าใช้มัน เป็นของ Microsoft กรรมสิทธิ์และไม่เคยได้รับการยอมรับจาก W3C
Steve K

13
IMHO นี่คือคำตอบที่น่ากลัว เป็นไปได้อย่างสมบูรณ์ในการจัดเรียงโหนด DOM ใหม่โดยไม่ทำให้เป็นอนุกรมและยกเลิกการเรียงซ้ำอีกครั้งและไม่ทำลายคุณสมบัติและ / หรือเหตุการณ์ใด ๆ ที่แนบมา
Alnitak

3
... แต่ถ้าคุณใช้ jQuery คุณจะทำอย่างไร
Matthew

332

บางสิ่งเช่นนี้

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); });

จากหน้านี้: http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/

โค้ดด้านบนจะเรียงลำดับรายการที่ไม่เรียงลำดับของคุณด้วยรหัส 'myUL'

หรือคุณสามารถใช้ปลั๊กอินเช่น TinySort https://github.com/Sjeiti/TinySort


6
บรรทัดสุดท้ายสามารถถูกแทนที่ด้วย $ (listitems) .appendTo (mylist); ?
Amir

26
HL Menken มีคำพูดที่อธิบายวิธีแก้ปัญหานี้: "สำหรับทุกปัญหามีวิธีแก้ปัญหาที่ง่ายสง่างามและผิด" กระบวนการนี้ทำงานในเวลา O (n ^ 2) มันไม่น่าสนใจกับรายการที่ค่อนข้างสั้น แต่ในรายการที่มีองค์ประกอบมากกว่า 100 รายการจะใช้เวลา 3-4 วินาทีในการจัดเรียงให้เสร็จ
นาธานที่แข็งแกร่ง

5
@ นาธาน: เกี่ยวกับ "สำหรับทุกปัญหามีวิธีแก้ปัญหาที่ง่ายสง่างามและผิด" - ดีการแก้ปัญหาไม่ถูกต้องไม่สวยงาม
โยฮันน์ฟิลิปป์สแตร ธ โทเซน

18
บางสิ่งอาจดูสง่างามและน่าสนใจ แต่ก็ยังล้มเหลว ความสง่างามไม่ได้หมายความถึงความสำเร็จ
Jane Panda

13
วิธีนี้ไม่ผิด มันตอบคำถาม OP ไม่ได้ระบุว่าเขาต้องการเรียงลำดับรายการมากกว่า 100 รายการ หากรายชื่อของเขาจะไม่ยาวเกิน 100 รายการการแก้ปัญหานี้เป็นที่ยอมรับอย่างสมบูรณ์ +1 สำหรับการชี้ให้เห็นว่าโซลูชันช้า -1 สำหรับการประกาศโซลูชันที่ตรงกับข้อกำหนดว่า 'ผิด'
Samurai Soul

94
$(".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;    
}

การสาธิตสด: http://jsbin.com/eculis/876/edit


15
นี่คือคำตอบที่ดีที่สุด $(".list li").sort(function(a, b){return ($(b).text()) < ($(a).text());}).appendTo('.list');ฉันก็ชอบมันอยู่ในแนวเดียวเช่นนี้ หนึ่งข้อสังเกต: .text()ควรเป็น.text().toUpperCase()
Jules Colle

น่าเสียดายที่โซลูชันนี้ใช้ไม่ได้กับ IE ในขณะที่คำตอบของ PatrickHecks ด้านล่างใช้ได้กับเบราว์เซอร์ทั้งหมด
patg

8
ระวังตัวเลือก! ".list li" จะเลือกแท็ก LI ลงทั้งหมดไม่ใช่เฉพาะรายการย่อย
Doug Domeny

3
@DougDomeny ถูกต้อง ดีกว่าที่จะโทร$(".list").children()ถ้าเป็นไปได้หรือตั้งค่าตัวเลือกที่มีความสัมพันธ์ของเด็กทันทีเช่น$(".list > li")
mroncetwice

1
BTW นี่คือลิงค์ไปยังซอฉันทำโดยใช้คำตอบนี้ ฉันตั้งรหัสเป็นฟังก์ชั่น all-in-one: jsfiddle.net/mroncetwice/t0whh6fL
mroncetwice

39

ในการทำให้งานนี้ใช้งานได้กับเบราว์เซอร์ทั้งหมดรวมถึง Chrome คุณต้องใช้ฟังก์ชัน callback ของ 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");

2
ไม่ควรลบองค์ประกอบ li ทั้งหมดออกจาก ul.myList ก่อนที่จะผนวกองค์ประกอบ li ที่เรียงลำดับไว้?
Daud

2
@Daud องค์ประกอบ LI ไม่จำเป็นต้องลบอย่างชัดเจน
Doug Domeny

1
การใช้. localeCompare จะเป็นการปรับปรุงสำหรับอักขระที่ไม่ใช่ ASCII
Doug Domeny

1
@DougDomeny ทำไมไม่ต้องการลบองค์ประกอบ li อย่างชัดเจน
bowserm

3
@bowserm วิธีการ appendTo จะย้ายองค์ประกอบ DOM แทนที่จะคัดลอก
Doug Domeny

31

หากคุณใช้ jQuery คุณสามารถทำได้:

$(function() {

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

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

});
<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>

โปรดทราบว่ากลับมาที่ 1 และ -1 (หรือ 0 และ 1) จากฟังก์ชั่นการเปรียบเทียบที่ไม่ถูกต้องอย่างแน่นอน


7

@ SolutionYogi คำตอบนั้นใช้งานได้อย่างมีเสน่ห์ แต่ดูเหมือนว่าการใช้ $ .each นั้นมีความตรงไปตรงมาและมีประสิทธิภาพน้อยกว่ารายการต่อท้ายโดยตรง:

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);

ซอ


$ ('# list'). empty () -> mylist.empty () น่าจะดีกว่า ไม่จำเป็นต้องแตะ DOM อีกครั้ง
Jacob van Lingen

แน่นอนฉันเพิ่งแก้ไขมัน!
Buzut

สิ่งนี้ไม่ทำงานใน Internet Explorer (ทดสอบกับรุ่น 10)
แช้ดจอห์นสัน

ฉันเพิ่งทดสอบกับ IE11 และอันที่จริงมันไม่ทำงาน แต่ SolutionYogi ไม่ทำงานภายใต้ IE11 …มันเหมาะกับคุณหรือเปล่า
Buzut

1

การปรับปรุงตามคำตอบของJeetendra Chauhan

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

ทำไมฉันถึงคิดว่ามันเป็นการปรับปรุง:

  1. ใช้eachเพื่อรองรับการทำงานบน ul มากกว่าหนึ่ง

  2. การใช้children('li')แทนที่จะ('ul li')เป็นสิ่งสำคัญเพราะเราต้องการดำเนินการกับลูกโดยตรงไม่ใช่ลูกหลาน

  3. การใช้ฟังก์ชั่นลูกศร(a,b)=>ดูดีขึ้น (ไม่รองรับ IE)

  4. ใช้วานิลลาinnerTextแทน$(a).text()การปรับปรุงความเร็ว

  5. การใช้วานิลลาlocaleCompareช่วยเพิ่มความเร็วในกรณีที่มีส่วนประกอบเท่ากัน

  6. การใช้appendTo(this)แทนการใช้ตัวเลือกอื่นจะทำให้แน่ใจว่าแม้ว่าตัวเลือกจะจับได้มากกว่าหนึ่ง ul ก็ไม่มีอะไรแตก


0

ฉันกำลังมองหาที่จะทำสิ่งนี้ด้วยตัวเองและฉันก็ไม่พอใจกับคำตอบใด ๆ ที่ให้ไว้เพียงเพราะฉันเชื่อว่าพวกเขาเป็นเวลากำลังสองและฉันต้องทำสิ่งนี้ในรายการยาวหลายร้อยรายการ

ฉันสิ้นสุดการขยาย jquery และโซลูชันของฉันใช้ jQuery แต่สามารถแก้ไขได้อย่างง่ายดายเพื่อใช้ javascript แบบตรง

ฉันเข้าถึงแต่ละรายการสองครั้งและดำเนินการเรียงลำดับแบบเชิงเส้นเดียวดังนั้นฉันคิดว่านี่น่าจะทำงานได้เร็วขึ้นมากบนชุดข้อมูลขนาดใหญ่ถึงแม้ว่าฉันจะยอมรับได้อย่างอิสระว่าฉันเข้าใจผิด:

sortList: function() {
   if (!this.is("ul") || !this.length)
      return
   else {
      var getData = function(ul) {
         var lis     = ul.find('li'),
             liData  = {
               liTexts : []
            }; 

         for(var i = 0; i<lis.length; i++){
             var key              = $(lis[i]).text().trim().toLowerCase().replace(/\s/g, ""),
             attrs                = lis[i].attributes;
             liData[key]          = {},
             liData[key]['attrs'] = {},
             liData[key]['html']  = $(lis[i]).html();

             liData.liTexts.push(key);

             for (var j = 0; j < attrs.length; j++) {
                liData[key]['attrs'][attrs[j].nodeName] = attrs[j].nodeValue;
             }
          }

          return liData;
       },

       processData = function (obj){
          var sortedTexts = obj.liTexts.sort(),
              htmlStr     = '';

          for(var i = 0; i < sortedTexts.length; i++){
             var attrsStr   = '',
                 attributes = obj[sortedTexts[i]].attrs;

             for(attr in attributes){
                var str = attr + "=\'" + attributes[attr] + "\' ";
                attrsStr += str;
             }

             htmlStr += "<li "+ attrsStr + ">" + obj[sortedTexts[i]].html+"</li>";
          }

          return htmlStr;

       };

       this.html(processData(getData(this)));
    }
}


0

HTML

<ul id="list">
    <li>alpha</li>
    <li>gamma</li>
    <li>beta</li>
</ul>

JavaScript

function sort(ul) {
    var ul = document.getElementById(ul)
    var liArr = ul.children
    var arr = new Array()
    for (var i = 0; i < liArr.length; i++) {
        arr.push(liArr[i].textContent)
    }
    arr.sort()
    arr.forEach(function(content, index) {
        liArr[index].textContent = content
    })
}

sort("list")

การสาธิต JSFiddle https://jsfiddle.net/97oo61nw/

ที่นี่เราจะผลักดันค่าทั้งหมดของliองค์ประกอบภายในulด้วยที่เฉพาะเจาะจงid(ซึ่งเราให้ไว้เป็นอาร์กิวเมนต์ฟังก์ชั่น) เพื่ออาร์เรย์arrและจัดเรียงโดยใช้วิธีการเรียง ()ซึ่งเรียงลำดับตัวอักษรตามค่าเริ่มต้น หลังจากarrเรียงลำดับแล้วเราจะวนรอบอาร์เรย์นี้โดยใช้วิธี forEach ()และเพียงแทนที่เนื้อหาข้อความของliองค์ประกอบทั้งหมดด้วยเนื้อหาที่เรียงลำดับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.