JQuery .each () al contrario


442

Sto usando JQuery per selezionare alcuni elementi in una pagina e poi spostarli nel DOM. Il problema che sto riscontrando è che devo selezionare tutti gli elementi nell'ordine inverso che JQuery vuole naturalmente selezionarli. Per esempio:

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

Voglio selezionare tutti gli elementi li e usare il comando .each () su di essi, ma voglio iniziare con l'articolo 5, quindi con l'articolo 4 ecc. È possibile?

Risposte:


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

10
Dovrebbe essere importante notare che l'indice non è invertito, quindi se vuoi solo fare gli ultimi tre, ad esempio, non puoi aspettarti <li>Item 5</li>di avere un indice di 0.
pathfinder

8
a David Andres: potresti aver dimenticato di aggiungere $ () prima di li. Ho fatto questo errore e ho ricevuto "undefined func".
Michal - wereda-net,

2
@DavidAndres: hai perso quello .get()che trasforma l'array avvolto jQuery in un normale array JS. L'array JS ha .reverse().
pila

1
Attenzione: Array.reverse()entrambi modifica l'array in posizione e restituisce l'array invertito. Quindi questa soluzione in realtà si basa su $ (). Get () che restituisce un nuovo array e non un riferimento ad alcuni jQuery o DOM array interni. Probabilmente una scommessa sicura entro i limiti di questo esempio. Caveat Coder.
Bob Stein,

404

Ti presento il modo più pulito di sempre, nella forma del plugin jquery più piccolo del mondo:

jQuery.fn.reverse = [].reverse;

Uso:

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

-Tutti i crediti a Michael Geary nel suo post qui: http://www.mail-archive.com/discuss@jquery.com/msg04261.html


Ok, sono d'accordo che è bello, ma perché funziona? Stai copiando (in modo approssimativo) Array.prototype.reverse in jQuery.prototype.reverse e quando viene chiamato l' thisoggetto ha proprietà numeriche e una proprietà length, quindi javascript può indicizzarlo e applicare una funzione array a un'istanza jQuery?
mlhDev

5
Dovrebbe essere importante notare che l'indice non è invertito, quindi se vuoi solo fare gli ultimi tre, ad esempio, non puoi aspettarti <li>Item 5</li>di avere un indice di 0.
pathfinder

1
@Matthew - Sì, hai capito bene. Quel codice copia davvero un riferimento a Array.prototype.reverseover jQuery.prototype.reverse. Molti dei metodi dell'array JavaScript funzionano bene su qualsiasi oggetto che assomigli abbastanza a un array, ovvero se l'oggetto ha .lengthproprietà di indice numeriche. reversenon dipende da una rappresentazione interna dell'array; accede la matrice utilizzando il normale .length, [0], [1]ecc proprio come codice di serie devi scrivere da soli.
Michael Geary,

8
Non è inutile creare un'istanza di un nuovo array solo per ottenere il suo reversemetodo? Non sarebbe più veloce semplicemente copiare un riferimento alla funzione Array.prototype.reverse, ad esempio jQuery.fn.reverse = Array.prototype.reverse;? Non così breve e "intelligente", ma più efficiente? Certo, questo sarà probabilmente impercettibile nei browser velocissimi di oggi, ma comunque ...
Zachelrath,

3
@zachelrath Sì, non riesco più a ottenere alcun tipo di separazione tra i risultati. Sembra che il 20% sia stato solo un colpo di fortuna. Ricorda, stai impostando la funzione una sola volta, quindi l'istanza avviene una sola volta, da lì la funzione è impostata.
Sandy Gifford,

64

Tu puoi fare

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

seguito da

$(selector).reverse().each(...) 

14
Questo approccio è stato originariamente proposto da John Resig (sviluppatore jQuery) nella mailing list di jQuery .
Chris Shouts,

20

Qui ci sono diverse opzioni per questo:

Primo : senza 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 qui

... e con jQuery:

Puoi usare questo:

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

Demo qui

Un altro modo, usando anche jQuery con reverse è:

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

Questa demo qui .

Un'alternativa in più è usare il length(conteggio degli elementi corrispondenti a quel selettore) e scendere da lì usando il indexdi ogni iterazione. Quindi puoi usare questo:

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

Questa demo qui

Un altro , un po 'correlato a quello sopra:

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

Demo qui


14

Preferisco creare un plug-in inverso, ad es

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

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

Utilizzo ad es .:

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

Mi piace anche questa idea / codice, ma non restituisce un oggetto concatenabile (che è invertito) come le risposte più votate :) Comunque, sicuramente un buon metodo per il modo in cui è impostato
Ian

Hai ragione. Non concatenabile, quindi non un plugin valido. Tuttavia, ho leggermente migliorato il codice, spostando il decrementatore nella condizione.
James Westgate,

8

Se non si desidera salvare il metodo in jQuery.fn, è possibile utilizzare

[].reverse.call($('li'));

Questo è quello che stavo cercando.
Alexander Dixon,

5

Ho dovuto fare un contrario su $ .each, quindi ho usato l'idea di Vinay:

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

ha funzionato bene, grazie


Questo non è giusto; questo dovrebbe essere $.each(collection.reverse(), ...).
Sophie Alpert,

@Ben Alpert - il tuo commento è imperfetto, perché la raccolta non è un vero array
vsync

4

Non è possibile eseguire l'iterazione all'indietro con jQuery per ciascuna funzione, ma è comunque possibile sfruttare la sintassi di jQuery.

Prova quanto segue:

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

Ho trovato Array.prototype.reversesuccesso con gli oggetti, così ho fatto una nuova funzione jQuery da usare come alternativa: jQuery.eachBack(). Esegue l'iterazione come jQuery.each()farebbe normalmente e memorizza ogni chiave in un array. Quindi inverte quell'array ed esegue il callback sull'array / oggetto originale nell'ordine delle chiavi invertite.

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

Penso che tu abbia bisogno

.parentsUntill()

1
Perché pensi che? E come lo useresti?
Bergi,

-2

Puoi anche provare

var arr = [].reverse.call($('li'))
arr.each(function(){ ... })
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.