Як я можу сортувати список за алфавітом за допомогою jQuery?


233

Я тут трохи не в глибині, і сподіваюся, що це насправді можливо.

Мені б хотілося викликати функцію, яка б сортувала всі елементи мого списку за алфавітом.

Я переглядав інтерфейс jQuery для сортування, але, здається, це не так. Будь-які думки?



Перевірте Underscore.js або Sugar.js .
Кріс Хайра

Відповіді:


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 перед сортуванням, ці асоціації тепер вказують на неправильні вузли після сортування.
Рудизм

13
Переміщення елементів через innerHTML - це погане рішення, оскільки вони не є тими ж елементами після сортування. Усі існуючі посилання на елементи втрачаються. Усі слухачі подій, пов’язані з JavaScript, втрачаються. Краще зберігати елементи замість innerHTML, використовувати функцію сортування (vals.sort (функція (a, b) {return b.innerHTML <a.innerHTML;})) та додаватиChild для переміщення елементів.
грегер

3
Бухуу внутрішнійHTML! Не використовуйте це. Це майно Microsoft, яке W3C ніколи не визнавало.
Стів К

13
ІМХО це жахлива відповідь. Цілком можливо переупорядкувати вузли DOM, не серіалізуючи їх і повторно десериалізуючи їх, і не знищуючи прикріплених властивостей та / або подій.
Альнітак

3
... але якби ви використовували jQuery, як би це зробити?
Метью

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/

Наведений вище код буде сортувати ваш не упорядкований список з id 'myUL'.

АБО ви можете використовувати плагін типу TinySort. https://github.com/Sjeiti/TinySort


6
Чи можна замінити останній рядок на $ (listitems) .appendTo (мій список); ?
Амір

26
HL Menken містить цитату, яка описує це рішення: "Для кожної проблеми є рішення, яке є простим, елегантним та неправильним". Цей процес запускається в O (n ^ 2) час. Це не помітно при відносно коротких списках, але для списку, що містить понад 100 елементів, потрібно тривати 3-4 секунди, щоб закінчити сортування.
Натан Сильний

5
@Nathan: Про "Для кожної проблеми є рішення, яке є простим, елегантним та неправильним." - ну неправильне рішення - це не елегантно.
Йоганн Філіп Стратхаузен

18
Щось може бути елегантним та інтригуючим для перегляду, але все-таки не виходить. Елегантність не означає успіху.
Джейн Панда

13
Це рішення не є помилковим. Це відповідає на питання. ОП не уточнила, що йому потрібно сортувати список із понад 100 пунктів. Якщо його список ніколи не буде довше 100 предметів, це рішення цілком прийнятно. +1 за вказівку, що рішення є повільним, -1 для оголошення рішення, яке відповідає вимогам як "неправильне".
Душа Самурая

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()
Жюль Колл

На жаль, це рішення не працює в IE, тоді як відповідь PatrickHecks нижче працює у всіх браузерах.
патг

8
Остерігайся селектора! ".list li" вибере всі похідні теги LI, а не лише безпосередніх дітей.
Doug Domeny

3
@DougDomeny має рацію. Краще зателефонувати $(".list").children(), якщо можливо, або налаштувати селектор з негайними стосунками з дитиною, наприклад$(".list > li")
mroncetwice

1
BTW Ось посилання на загадку, яку я зробив, використовуючи цю відповідь. Я встановив код як функцію "все в одному": jsfiddle.net/mroncetwice/t0whh6fL
mroncetwice

39

Щоб ця робота працювала з усіма браузерами, включаючи Chrome, вам потрібно зробити функцію зворотного дзвінка sort () return -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?
Дауд

2
@Daud, елементи LI не потрібно явно видаляти.
Doug Domeny

1
Використання .localeCompare буде вдосконаленням для символів, що не належать до ASCII.
Doug Domeny

1
@DougDomeny, чому елементи лі не потрібно явно видаляти?
цибуля

3
@bowserm, метод appendTo переміщує елементи DOM, а не копіює їх.
Дуг Домені

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 є менш простим та ефективним, ніж безпосередньо додавання 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);

Скрипка


$ ('# list'). empty () -> mylist.empty () було б краще. Не потрібно торкатися до DOM знову.
Якоб ван Лінген

Абсолютно, я просто це виправив!
Бузут

Це не працює в Internet Explorer (перевірено версією 10).
Чад Джонсон

Я щойно тестував IE11 і насправді він не працює. Але код SolutionYogi не працював ні під IE11 ... Це працювало для вас?
Бузут

1

вдосконалення на основі джеетендра Чаухан відповіді «s

$('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та сортування за допомогою методу sort (), який сортується за алфавітом за замовчуванням. Після arrсортування масиву ми обв'язуємо цей масив методом forEach () і просто замінюємо текстовий вміст усіх liелементів на відсортований вміст

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.