JQuery .each () do tyłu

442

Używam JQuery, aby wybrać niektóre elementy na stronie, a następnie przenieść je w DOM. Problemem jest to, że muszę wybrać wszystkie elementy w odwrotnej kolejności, aby JQuery naturalnie je wybrało. Na przykład:

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

Chcę wybrać wszystkie pozycje li i użyć na nich polecenia .each (), ale chcę zacząć od pozycji 5, a następnie pozycji 4 itd. Czy to możliwe?

Jack Mills
źródło

Odpowiedzi:

681
$($("li").get().reverse()).each(function() { /* ... */ });
Joe Chung
źródło
10
Należy pamiętać, że indeks nie jest odwrócony, więc jeśli na przykład chcesz wykonać tylko trzy ostatnie, nie możesz oczekiwać, że będziesz <li>Item 5</li>mieć indeks 0.
pathfinder
8
do Davida Andresa: być może zapomniałeś dodać dodatkowe $ () przed li. Popełniłem ten błąd i otrzymałem „niezdefiniowany func”.
Michał - wereda-net
2
@DavidAndres: Przegapiłeś .get()tablicę owiniętą jQuery w zwykłą tablicę JS. Tablica JS ma .reverse().
sztaplowane
1
Uwaga: Array.reverse()zarówno modyfikuje tablicę w miejscu, jak i zwraca tablicę odwróconą. Zatem to rozwiązanie faktycznie polega na zwróceniu nowej tablicy przez $ (). Get (), a nie odwołanie do wewnętrznej tablicy jQuery lub DOM. Prawdopodobnie bezpieczny zakład w ramach tego przykładu. Caveat Coder.
Bob Stein
404

Przedstawiam Ci najczystszy sposób w historii, w postaci najmniejszej na świecie wtyczki jquery:

jQuery.fn.reverse = [].reverse;

Stosowanie:

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

- Podziękowania dla Michaela Geary'ego w jego poście tutaj: http://www.mail-archive.com/[email protected]/msg04261.html

Waldo Hampton
źródło
Ok, zgadzam się, że to fajnie, ale dlaczego to działa? Kopiujesz (luźno mówiąc) Array.prototype.reverse do jQuery.prototype.reverse, a gdy jest wywołane, thisobiekt ma właściwości numeryczne i właściwość length, więc javascript może go zindeksować i zastosować funkcję tablicową do instancji jQuery?
mlhDev,
5
Należy pamiętać, że indeks nie jest odwrócony, więc jeśli na przykład chcesz wykonać tylko trzy ostatnie, nie możesz oczekiwać, że będziesz <li>Item 5</li>mieć indeks 0.
pathfinder
1
@Matthew - Tak, dobrze to rozumiesz. Ten kod rzeczywiście kopiuje odniesienie do Array.prototype.reverseover jQuery.prototype.reverse. Wiele metod tablicowych JavaScript działa dobrze na każdym obiekcie, który wygląda wystarczająco jak tablica - to znaczy, jeśli obiekt ma .lengthwłaściwości indeksu numerycznego. reversenie zależy od wewnętrznej reprezentacji tablicy; to uzyskuje dostęp do tablicy przy użyciu normalnego .length, [0], [1]itd., tak jak kod tablicy chcesz napisać samemu.
Michael Geary
8
Czy nie jest marnotrawstwem tworzenie nowego Array tylko po to, aby uzyskać jego reversemetodę? Czy nie byłoby szybciej po prostu skopiować odwołanie do funkcji Array.prototype.reverse, np. jQuery.fn.reverse = Array.prototype.reverse;? Nie tak krótki i „sprytny”, ale bardziej wydajny? Wprawdzie będzie to prawdopodobnie niezauważalne w dzisiejszych błyskawicznych przeglądarkach, ale nadal ...
zachelrath
3
@zachelrath Tak, nie mogę już uzyskać żadnej separacji między wynikami. Wygląda na to, że 20% to był tylko przypadek. Pamiętaj, że ustawiasz funkcję tylko raz, więc tworzenie instancji odbywa się tylko raz, stamtąd funkcja jest ustawiana.
Sandy Gifford,
64

Możesz to zrobić

jQuery.fn.reverse = function() {
    return this.pushStack(this.get().reverse(), arguments);
}; 

śledzony przez

$(selector).reverse().each(...) 
Vinay Sajip
źródło
14
Takie podejście zostało pierwotnie zaproponowane przez Johna Resiga (programistę jQuery) na liście mailingowej jQuery .
Chris Shouts
20

Oto różne opcje:

Po pierwsze : bez 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;
});

Demo tutaj

... oraz z jQuery:

Możesz użyć tego:

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

Demo tutaj

Innym sposobem korzystania z jQuery z odwrotnością jest:

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

To demo tutaj .

Jeszcze jedną alternatywą jest użycie length(liczba elementów pasujących do tego selektora) i zejście stamtąd za pomocą indexkażdej iteracji. Następnie możesz użyć tego:

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

To demo tutaj

Jeszcze jedno , trochę związane z powyższym:

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

Demo tutaj

Sergio
źródło
14

Wolę tworzyć odwrotną wtyczkę np

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

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

Zastosowanie np .:

$('#product-panel > div').reverse(function(i, e) {
    alert(i);
    alert(e);
});
James Westgate
źródło
Podoba mi się również ten pomysł / kod, ale nie zwraca obiektu łańcuchowego (który jest odwrócony), jak wyżej głosowane odpowiedzi :) Mimo to zdecydowanie dobra metoda konfiguracji
Ian
Masz rację. Nie można go łańcuchować, więc nie jest prawidłową wtyczką. Poprawiono nieco kod, przenosząc dekrementator do stanu.
James Westgate,
8

Jeśli nie chcesz zapisać metody w pliku jQuery.fn, możesz użyć

[].reverse.call($('li'));
yuraki
źródło
Właśnie tego szukałem.
Alexander Dixon
5

Musiałem zrobić odwrotność dla $ .each, więc skorzystałem z pomysłu Vinay:

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

działało ładnie, dzięki

finklez
źródło
To nie w porządku; tak powinno być $.each(collection.reverse(), ...).
Sophie Alpert
@Ben Alpert - twój komentarz jest błędny, ponieważ kolekcja nie jest prawdziwą tablicą
vsync
4

Nie można iterować wstecz z każdą funkcją jQuery, ale nadal można korzystać ze składni jQuery.

Spróbuj wykonać następujące czynności:

//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
}
David Andres
źródło
2

Znalazłem Array.prototype.reversepowiodła się z obiektami, więc zrobiłem nową funkcję jQuery do wykorzystania jako alternatywa: jQuery.eachBack(). Powtarza się tak, jak zwykle jQuery.each(), i zapisuje każdy klucz w tablicy. Następnie odwraca tę tablicę i wykonuje wywołanie zwrotne na oryginalnej tablicy / obiekcie w kolejności odwróconych kluczy.

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);
}
NRTRX
źródło
-2

Myślę, że potrzebujesz

.parentsUntill()
Jimmy M.
źródło
1
Dlaczego myślisz, że? A jak byś tego użył?
Bergi
-2

Możesz także spróbować

var arr = [].reverse.call($('li'))
arr.each(function(){ ... })
mattyfew
źródło