JQuery .each () vers l'arrière

442

J'utilise JQuery pour sélectionner certains éléments sur une page, puis les déplacer dans le DOM. Le problème que j'ai est que je dois sélectionner tous les éléments dans l'ordre inverse que JQuery veut naturellement les sélectionner. Par exemple:

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

Je veux sélectionner tous les éléments li et utiliser la commande .each () dessus, mais je veux commencer par l'élément 5, puis l'élément 4, etc. Est-ce possible?

Jack Mills
la source

Réponses:

681
$($("li").get().reverse()).each(function() { /* ... */ });
Joe Chung
la source
10
Il devrait être important de noter que l'indice n'est pas inversé, donc si vous ne voulez faire que les trois derniers, par exemple, vous ne pouvez pas vous attendre <li>Item 5</li>à avoir un indice de 0.
pathfinder
8
à David Andres: vous avez peut-être oublié d'ajouter $ () avant li. J'ai fait cette erreur et j'ai reçu "func indéfini".
Michal - wereda-net
2
@DavidAndres: Vous avez manqué le .get()qui transforme le tableau encapsulé jQuery en un tableau JS ordinaire. Le tableau JS a .reverse().
stackular
1
Attention: à la Array.reverse()fois modifie le tableau en place et renvoie le tableau inversé. Donc, cette solution repose en fait sur $ (). Get () renvoyant un nouveau tableau, et non une référence à un tableau jQuery ou DOM interne. Probablement une valeur sûre dans les limites de cet exemple. Caveat Coder.
Bob Stein
404

Je vous présente la manière la plus propre de tous les temps, sous la forme du plus petit plugin jquery au monde:

jQuery.fn.reverse = [].reverse;

Usage:

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

-Tous les remerciements à Michael Geary dans son article ici: http://www.mail-archive.com/[email protected]/msg04261.html

Waldo Hampton
la source
Ok, je suis d'accord, c'est cool, mais pourquoi ça marche? Vous copiez (vaguement) Array.prototype.reverse vers jQuery.prototype.reverse, et lorsqu'il est appelé, l' thisobjet a des propriétés numériques et une propriété de longueur, donc javascript peut l'indexer et peut appliquer une fonction de tableau à une instance jQuery?
mlhDev
5
Il devrait être important de noter que l'indice n'est pas inversé, donc si vous ne voulez faire que les trois derniers, par exemple, vous ne pouvez pas vous attendre <li>Item 5</li>à avoir un indice de 0.
pathfinder
1
@Matthew - Oui, vous comprenez bien. Ce code copie en effet une référence à Array.prototype.reverseover to jQuery.prototype.reverse. De nombreuses méthodes de tableau JavaScript fonctionneront correctement sur tout objet qui ressemble suffisamment à un tableau - c'est-à-dire si l'objet a .lengthdes propriétés d'index numérique. reversene dépend pas d'une représentation interne du tableau; il accède au tableau en utilisant la normale .length, [0], [1]etc. , tout comme le code de tableau que vous souhaitez vous écrivez.
Michael Geary
8
N'est-il pas inutile d'instancier un nouveau tableau juste pour obtenir sa reverseméthode? Ne serait-il pas plus rapide de copier simplement une référence à la fonction Array.prototype.reverse, par exemple jQuery.fn.reverse = Array.prototype.reverse;? Pas aussi court et "intelligent", mais plus efficace? Certes, cela sera probablement imperceptible dans les navigateurs
ultra
3
@zachelrath Ouais, je ne peux plus séparer les résultats. Il semble que 20% n'était qu'un coup de chance. N'oubliez pas que vous ne définissez la fonction qu'une seule fois, donc l'instanciation ne se produit qu'une seule fois, à partir de là, la fonction est définie.
Sandy Gifford
64

Tu peux faire

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

suivi par

$(selector).reverse().each(...) 
Vinay Sajip
la source
14
Cette approche a été initialement proposée par John Resig (développeur jQuery) sur la liste de diffusion jQuery .
Chris Shouts le
20

Voici différentes options pour cela:

D'abord : sans 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;
});

Démo ici

... et avec jQuery:

Vous pouvez utiliser ceci:

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

Démo ici

Une autre façon, en utilisant également jQuery avec reverse est:

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

Cette démo ici .

Une autre alternative consiste à utiliser le length(nombre d'éléments correspondant à ce sélecteur) et à descendre à partir de là en utilisant le indexde chaque itération. Ensuite, vous pouvez utiliser ceci:

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

Cette démo ici

Un de plus , un peu lié à celui ci-dessus:

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

Démo ici

Sergio
la source
14

Je préfère créer un plug-in inverse, par exemple

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

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

Utilisation par exemple:

$('#product-panel > div').reverse(function(i, e) {
    alert(i);
    alert(e);
});
James Westgate
la source
J'aime aussi cette idée / ce code, mais il ne renvoie pas un objet chaînable (qui est inversé) comme les réponses les plus votées :) Pourtant, certainement une bonne méthode pour la façon dont il est configuré
Ian
Tu as raison. Pas chaînable donc pas un plugin valide. Cependant, nous avons légèrement amélioré le code, en déplaçant le décrémenteur dans la condition.
James Westgate
8

Si vous ne souhaitez pas enregistrer la méthode dans jQuery.fn, vous pouvez utiliser

[].reverse.call($('li'));
yurakis
la source
C'est ce que je cherchais.
Alexander Dixon,
5

J'avais besoin de faire un reverse sur $ .each donc j'ai utilisé l'idée de Vinay:

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

a bien fonctionné, merci

finklez
la source
Ce n'est pas juste; cela devrait juste être $.each(collection.reverse(), ...).
Sophie Alpert
@Ben Alpert - votre commentaire est défectueux, car la collection n'est pas un véritable tableau
vsync
4

Vous ne pouvez pas parcourir en arrière avec chaque fonction jQuery, mais vous pouvez toujours tirer parti de la syntaxe jQuery.

Essayez ce qui suit:

//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
la source
2

J'ai trouvé Array.prototype.reversesans succès avec des objets, donc je fait une nouvelle fonction de jQuery à utiliser comme une alternative: jQuery.eachBack(). Il parcourt comme d'habitude jQuery.each()et stocke chaque clé dans un tableau. Il inverse ensuite ce tableau et effectue le rappel sur le tableau / objet d'origine dans l'ordre des clés inversées.

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
la source
-2

Je pense que tu as besoin

.parentsUntill()
Jimmy M
la source
1
Pourquoi pensez-vous cela? Et comment l'utiliseriez-vous?
Bergi
-2

Vous pouvez aussi essayer

var arr = [].reverse.call($('li'))
arr.each(function(){ ... })
mattyfew
la source