JQuery .each () назад


442

Я використовую JQuery для вибору деяких елементів на сторінці, а потім переміщую їх у DOM. Проблема, яку я маю, полягає в тому, що мені потрібно вибрати всі елементи у зворотному порядку, що JQuery, звичайно, хоче їх вибрати. Наприклад:

<ul>
   <li>Item 1</li>
   <li>Item 2</li>
   <li>Item 3</li>
   <li>Item 4</li>
   <li>Item 5</li>
</ul>

Я хочу вибрати всі елементи li та використати на них команду .each (), але я хочу почати з пункту 5, потім із пункту 4 тощо. Чи можливо це?

Відповіді:


681
$($("li").get().reverse()).each(function() { /* ... */ });

10
Слід зауважити, що індекс не змінюється, тому, якщо ви хочете виконати лише три останніх, наприклад, ви не можете розраховувати <li>Item 5</li>на індекс 0.
pathfinder

8
для Девіда Андреса: можливо, ви забули додати додаткові $ () перед li. Я зробив цю помилку і отримав "невизначений функцію".
Міхал - wereda-net

2
@DavidAndres: Ви пропустили те, .get()що перетворює обернутий масив jQuery у звичайний масив JS. Масив JS має .reverse().
stackular

1
Увага: Array.reverse()обидва модифікують масив на місці і повертають повернутий масив. Таким чином, це рішення фактично покладається на $ (). Get (), що повертає новий масив, а не посилання на якийсь внутрішній масив jQuery або DOM. Можливо, безпечна ставка в межах цього прикладу. Caveat Coder.
Боб Штейн

404

Я представляю вам найчистіший спосіб, у формі найменшого плагіну jquery в світі:

jQuery.fn.reverse = [].reverse;

Використання:

$('jquery-selectors-go-here').reverse().each(function () {
    //business as usual goes here
});

-Всі заслуги Майкла Гірі в його публікації тут: http://www.mail-archive.com/discuss@jquery.com/msg04261.html


Гаразд, я згоден, це круто, але чому це працює? Ви копіюєте (слабко кажучи) Array.prototype.reverse в jQuery.prototype.reverse, а коли він викликається, thisоб'єкт має числові властивості та властивість довжини, тож javascript може його індексувати і може застосувати функцію масиву до екземпляра jQuery?
mlhDev

5
Слід зауважити, що індекс не змінюється, тому, якщо ви хочете виконати лише три останніх, наприклад, ви не можете розраховувати <li>Item 5</li>на індекс 0.
pathfinder

1
@Matthew - Так, ти це правильно розумієш. Цей код дійсно скопіювати посилання на Array.prototype.reverseдо jQuery.prototype.reverse. Багато методів масиву JavaScript добре працюватимуть на будь-якому об'єкті, який досить схожий на масив - тобто якщо об’єкт має .lengthі властивості числового індексу. reverseне залежить від якогось внутрішнього представлення масиву; він отримує доступ до масиву , використовуючи нормальний .length, [0], і [1]т.д. так же , як код масиву ви пишете самі.
Майкл Гірі

8
Хіба не марно створювати новий масив просто для того, щоб отримати його reverseметод? Чи не було б швидше просто скопіювати посилання на функцію Array.prototype.reverse, наприклад jQuery.fn.reverse = Array.prototype.reverse;? Не такий короткий і «розумний», але ефективніший? Справді, це, мабуть, буде непомітно у сучасних браузерних браузерах, але все ж ...
zachelrath

3
@zachelrath Так, я більше не можу отримати ніякого поділу між результатами. Виглядає так, що 20% були просто смітником. Пам'ятайте, ви налаштовуєте функцію лише один раз, тому екземпляр відбувається лише один раз, звідти функція встановлена.
Сенді Гіффорд


20

Ось такі варіанти для цього:

По-перше : без jQuery:

var lis = document.querySelectorAll('ul > li');
var contents = [].map.call(lis, function (li) {
    return li.innerHTML;
}).reverse().forEach(function (content, i) {
    lis[i].innerHTML = content;
});

Демо тут

... та з jQuery:

Ви можете скористатися цим:

$($("ul > li").get().reverse()).each(function (i) {
    $(this).text( 'Item ' + (++i));
});

Демо тут

Ще один спосіб, використовуючи також jQuery з реверсом :

$.fn.reverse = [].reverse;
$("ul > li").reverse().each(function (i) {
    $(this).text( 'Item ' + (++i));
});

Це демо тут .

Ще однією альтернативою є використання length(кількість елементів, що відповідають цьому селектору) та спуск звідти, використовуючи indexкожну ітерацію. Тоді ви можете скористатися цим:

var $li = $("ul > li");
$li.each(function (i) {
    $(this).text( 'Item ' + ($li.length - i));
});

Це демо тут

Ще один , пов'язаний із вищезгаданим:

var $li = $("ul > li");
$li.text(function (i) {
    return 'Item ' + ($li.length - i);
});

Демо тут


14

Я вважаю за краще створювати зворотний плагін, наприклад

jQuery.fn.reverse = function(fn) {       
   var i = this.length;

   while(i--) {
       fn.call(this[i], i, this[i])
   }
};

Використання, наприклад:

$('#product-panel > div').reverse(function(i, e) {
    alert(i);
    alert(e);
});

Мені також подобається ця ідея / код, але вона не повертає досяжний об’єкт (який є зворотним), як відповіді з більш високим голосом :) Все-таки, безумовно, хороший метод способу його налаштування
Ян

Ти правий. Неможливо отримати, тому не допустимий плагін. Хоча трохи вдосконалили код, перемістивши декреметр у стан.
Джеймс Вестгейт


5

Потрібно зробити реверс на $ .each, тому я використав ідею Vinay:

//jQuery.each(collection, callback) =>
$.each($(collection).get().reverse(), callback func() {});

добре працювали, дякую


Це неправильно; це просто має бути $.each(collection.reverse(), ...).
Софі Альперт

@Ben Alpert - ваш коментар хибний, тому що колекція не є справжнім масивом
vsync

4

Ви не можете повторити назад функцію jQuery кожної функції, але ви все одно можете використовувати синтаксис jQuery.

Спробуйте наступне:

//get an array of the matching DOM elements   
var liItems = $("ul#myUL li").get();

//iterate through this array in reverse order    
for(var i = liItems.length - 1; i >= 0; --i)
{
  //do Something
}

2

Я знайшов Array.prototype.reverseневдалий з об'єктами, так що я зробив нову функцію JQuery , щоб використовувати в якості альтернативи: jQuery.eachBack(). Він повторюється, як звичайно jQuery.each(), і зберігає кожен ключ у масив. Потім він реверсує цей масив і виконує зворотний виклик на початковому масиві / об'єкті в порядку повернених клавіш.

jQuery.eachBack=function (obj, callback) {
    var revKeys=[]; $.each(obj,function(rind,rval){revKeys.push(rind);}); 
    revKeys.reverse();
    $.each(revKeys,function (kind,i){
        if(callback.call(obj[i], i, obj[i]) === false) {    return false;}
    });
    return obj;
}   
jQuery.fn.eachBack=function (callback,args) {
    return jQuery.eachBack(this, callback, args);
}


-2

Ви також можете спробувати

var arr = [].reverse.call($('li'))
arr.each(function(){ ... })
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.