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?

Réponses:


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

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/discuss@jquery.com/msg04261.html


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(...) 

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


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);
});

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'));

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


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
}

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);
}

-2

Je pense que tu as besoin

.parentsUntill()

1
Pourquoi pensez-vous cela? Et comment l'utiliseriez-vous?
Bergi

-2

Vous pouvez aussi essayer

var arr = [].reverse.call($('li'))
arr.each(function(){ ... })
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.