JQuery .each () rückwärts

442

Ich verwende JQuery, um einige Elemente auf einer Seite auszuwählen und sie dann im DOM zu verschieben. Das Problem, das ich habe, ist, dass ich alle Elemente in der umgekehrten Reihenfolge auswählen muss, in der JQuery sie natürlich auswählen möchte. Zum Beispiel:

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

Ich möchte alle li-Elemente auswählen und den Befehl .each () für sie verwenden, aber ich möchte mit Element 5, dann Element 4 usw. beginnen. Ist dies möglich?

Jack Mills
quelle

Antworten:

681
$($("li").get().reverse()).each(function() { /* ... */ });
Joe Chung
quelle
10
Es sollte wichtig sein zu beachten, dass der Index nicht umgekehrt wird. Wenn Sie also beispielsweise nur die letzten drei ausführen möchten, können Sie nicht <li>Item 5</li>mit einem Index von 0 rechnen .
Pathfinder
8
an David Andres: Vielleicht haben Sie vergessen, vor li zusätzliche $ () hinzuzufügen. Ich habe diesen Fehler gemacht und "undefined func" erhalten.
Michal - wereda-net
2
@DavidAndres: Sie haben das verpasst, das .get()das mit jQuery umschlossene Array in ein gewöhnliches JS-Array verwandelt. Das JS-Array hat .reverse().
Stapel
1
Achtung: Array.reverse()beide ändert die Anordnung an Ort und Stelle und gibt die umgekehrte Anordnung. Diese Lösung basiert also tatsächlich darauf, dass $ (). Get () ein neues Array zurückgibt und nicht auf ein internes jQuery- oder DOM-Array verweist. Wahrscheinlich eine sichere Wette innerhalb der Grenzen dieses Beispiels. Vorbehaltscodierer.
Bob Stein
404

Ich präsentiere Ihnen den saubersten Weg aller Zeiten in Form des kleinsten JQuery-Plugins der Welt:

jQuery.fn.reverse = [].reverse;

Verwendungszweck:

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

- Alles Gute an Michael Geary in seinem Beitrag hier: http://www.mail-archive.com/[email protected]/msg04261.html

Waldo Hampton
quelle
Ok, ich stimme zu, das ist cool, aber warum funktioniert es? Sie kopieren (lose gesagt) Array.prototype.reverse nach jQuery.prototype.reverse. Wenn es aufgerufen wird, verfügt das thisObjekt über numerische Eigenschaften und eine Längeneigenschaft, sodass Javascript es indizieren und eine Array-Funktion auf eine jQuery-Instanz anwenden kann.
mlhDev
5
Es sollte wichtig sein zu beachten, dass der Index nicht umgekehrt wird. Wenn Sie also beispielsweise nur die letzten drei ausführen möchten, können Sie nicht <li>Item 5</li>mit einem Index von 0 rechnen .
Pathfinder
1
@ Matthew - Ja, du verstehst es richtig. Dieser Code kopiert tatsächlich einen Verweis auf Array.prototype.reverseover to jQuery.prototype.reverse. Viele der JavaScript-Array-Methoden funktionieren problemlos für alle Objekte, die wie ein Array aussehen - wenn das Objekt über .lengthnumerische Indexeigenschaften verfügt. reversehängt nicht von einer internen Darstellung des Arrays ab; es greift auf das Array die normale Verwendung .length, [0], [1]usw. wie Array Code , den Sie selbst schreiben würde.
Michael Geary
8
Ist es nicht verschwenderisch, ein neues Array zu instanziieren, nur um seine reverseMethode zu erhalten? Wäre es nicht schneller, einfach einen Verweis auf die Funktion zu kopieren Array.prototype.reverse, z jQuery.fn.reverse = Array.prototype.reverse;. Nicht so kurz und "clever", aber effizienter? Zugegeben, dies wird in den heutigen blitzschnellen Browsern wahrscheinlich nicht
bemerkt
3
@zachelrath Ja, ich kann keine Trennung mehr zwischen den Ergebnissen feststellen. Es sieht so aus, als wären 20% nur ein Zufall. Denken Sie daran, dass Sie die Funktion nur einmal einstellen, sodass die Instanziierung nur einmal erfolgt. Von dort aus wird die Funktion eingestellt.
Sandy Gifford
64

Du kannst tun

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

gefolgt von

$(selector).reverse().each(...) 
Vinay Sajip
quelle
14
Dieser Ansatz wurde ursprünglich von John Resig (jQuery-Entwickler) auf der jQuery-Mailingliste vorgeschlagen .
Chris Shouts
20

Hierfür gibt es verschiedene Möglichkeiten:

Erstens : ohne 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 hier

... und mit jQuery:

Sie können dies verwenden:

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

Demo hier

Eine andere Möglichkeit, auch jQuery mit Reverse zu verwenden, ist:

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

Diese Demo hier .

Eine weitere Alternative besteht darin, die length(Anzahl der Elemente, die mit diesem Selektor übereinstimmen) zu verwenden und von dort mit der indexjeder Iteration nach unten zu gehen . Dann können Sie dies verwenden:

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

Diese Demo hier

Eine weitere , die irgendwie mit der oben genannten verwandt ist:

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

Demo hier

Sergio
quelle
14

Ich ziehe es vor, ein Reverse-Plug-In zu erstellen, z

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

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

Verwendung zB:

$('#product-panel > div').reverse(function(i, e) {
    alert(i);
    alert(e);
});
James Westgate
quelle
Ich mag diese Idee / diesen Code auch, aber sie gibt kein verkettbares Objekt (das umgekehrt ist) wie die höher bewerteten Antworten zurück :) Trotzdem definitiv eine gute Methode für die Art und Weise, wie es eingerichtet ist
Ian
Du hast recht. Nicht verkettbar, also kein gültiges Plugin. Habe den Code allerdings leicht verbessert und den Dekrementierer in den Zustand versetzt.
James Westgate
8

Wenn Sie die Methode nicht in jQuery.fn speichern möchten, können Sie sie verwenden

[].reverse.call($('li'));
Yurakis
quelle
Das habe ich gesucht.
Alexander Dixon
5

Musste ein Reverse für $ .each machen, also habe ich die Vinay-Idee verwendet:

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

hat gut funktioniert, danke

Finklez
quelle
Das ist nicht richtig; das sollte einfach so sein $.each(collection.reverse(), ...).
Sophie Alpert
@ Ben Alpert - Ihr Kommentar ist fehlerhaft, weil Sammlung kein echtes Array ist
vsync
4

Sie können mit der jQuery-Funktion nicht jede Funktion rückwärts durchlaufen, aber Sie können trotzdem die jQuery-Syntax nutzen.

Versuche Folgendes:

//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
quelle
2

Ich fand es Array.prototype.reversemit Objekten nicht erfolgreich, daher habe ich eine neue jQuery-Funktion erstellt, die als Alternative verwendet werden kann : jQuery.eachBack(). Es iteriert wie gewohnt jQuery.each()und speichert jeden Schlüssel in einem Array. Anschließend wird das Array umgekehrt und der Rückruf für das ursprüngliche Array / Objekt in der Reihenfolge der umgekehrten Schlüssel ausgeführt.

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
quelle
-2

Ich denke du brauchst

.parentsUntill()
Jimmy M.
quelle
1
Warum denkst du, dass? Und wie würden Sie es verwenden?
Bergi
-2

Sie können es auch versuchen

var arr = [].reverse.call($('li'))
arr.each(function(){ ... })
Mattyfew
quelle