JQuery .each () al revés

442

Estoy usando JQuery para seleccionar algunos elementos en una página y luego moverlos en el DOM. El problema que tengo es que necesito seleccionar todos los elementos en el orden inverso que JQuery naturalmente quiere seleccionarlos. Por ejemplo:

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

Quiero seleccionar todos los elementos li y usar el comando .each () en ellos, pero quiero comenzar con el elemento 5, luego el elemento 4, etc. ¿Es esto posible?

Jack Mills
fuente

Respuestas:

681
$($("li").get().reverse()).each(function() { /* ... */ });
Joe Chung
fuente
10
Debe ser importante tener en cuenta que el índice no se invierte, por lo que si solo desea hacer los últimos tres, por ejemplo, no puede esperar <li>Item 5</li>tener un índice de 0.
pathfinder
8
a David Andres: tal vez se te olvidó agregar $ () antes de li. Cometí este error y recibí "func indefinido".
Michal - wereda-net
2
@DavidAndres: Te perdiste el .get()que convierte la matriz envuelta jQuery en una matriz JS normal. La matriz JS tiene .reverse().
stackular
1
Precaución: Array.reverse()ambos modifican la matriz en su lugar y devuelven la matriz invertida. Entonces, esta solución realmente depende de que $ (). Get () devuelva una nueva matriz, y no una referencia a alguna matriz interna jQuery o DOM. Probablemente una apuesta segura dentro de los límites de este ejemplo. Codificador de advertencia.
Bob Stein
404

Te presento la forma más limpia de la historia, en forma del complemento jquery más pequeño del mundo:

jQuery.fn.reverse = [].reverse;

Uso:

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

-Todos los créditos a Michael Geary en su publicación aquí: http://www.mail-archive.com/[email protected]/msg04261.html

Waldo Hampton
fuente
Ok, estoy de acuerdo, eso es genial, pero ¿por qué funciona? Está copiando (en términos generales) Array.prototype.reverse a jQuery.prototype.reverse, y cuando se llama, el thisobjeto tiene propiedades numéricas y una propiedad de longitud, ¿entonces JavaScript puede indexarlo y puede aplicar una función de matriz a una instancia de jQuery?
mlhDev
55
Debe ser importante tener en cuenta que el índice no se invierte, por lo que si solo desea hacer los últimos tres, por ejemplo, no puede esperar <li>Item 5</li>tener un índice de 0.
pathfinder
1
@Matthew - Sí, lo entiendes bien. Ese código copia una referencia a Array.prototype.reverseover to jQuery.prototype.reverse. Muchos de los métodos de matriz de JavaScript funcionarán bien en cualquier objeto que se parezca lo suficiente a una matriz, es decir, si el objeto tiene .lengthpropiedades de índice numérico. reverseno depende de alguna representación interna de la matriz; accede a la matriz usando el normal .length, etc. [0], [1]al igual que el código de matriz que escribiría usted mismo.
Michael Geary
8
¿No es un desperdicio crear una instancia de una nueva matriz solo para obtener su reversemétodo? ¿No sería más rápido copiar una referencia a la función Array.prototype.reverse, por ejemplo jQuery.fn.reverse = Array.prototype.reverse;? ¿No tan corto e "inteligente", pero más eficiente? Es cierto que esto probablemente pasará desapercibido en los navegadores rápidos de hoy en día, pero aún así ...
zachelrath
3
@zachelrath Sí, ya no puedo tener ningún tipo de separación entre los resultados. Parece que ese 20% fue solo una casualidad. Recuerde, solo está configurando la función una vez, por lo que la creación de instancias solo ocurre una vez, desde allí se establece la función.
Sandy Gifford
64

Tu puedes hacer

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

seguido por

$(selector).reverse().each(...) 
Vinay Sajip
fuente
14
Este enfoque fue propuesto originalmente por John Resig (desarrollador de jQuery) en la lista de correo de jQuery .
Chris grita el
20

Aquí hay diferentes opciones para esto:

Primero : sin 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 aquí

... y con jQuery:

Puedes usar esto:

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

Demo aquí

Otra forma, usando también jQuery con reverse es:

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

Esta demo aquí .

Una alternativa más es usar el length(conteo de elementos que coinciden con ese selector) y bajar desde allí usando el indexde cada iteración. Entonces puedes usar esto:

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

Esta demo aquí

Uno más , más o menos relacionado con el anterior:

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

Demo aquí

Sergio
fuente
14

Prefiero crear un complemento inverso, por ejemplo

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

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

Uso, por ejemplo:

$('#product-panel > div').reverse(function(i, e) {
    alert(i);
    alert(e);
});
James Westgate
fuente
También me gusta esta idea / código, pero no devuelve un objeto encadenable (que se invierte) como las respuestas con más votos :) Aún así, definitivamente es un buen método para la forma en que está configurado
Ian
Tienes razón. No es encadenable, por lo que no es un complemento válido. Sin embargo, he mejorado ligeramente el código, moviendo el decrementador a la condición.
James Westgate
8

Si no desea guardar el método en jQuery.fn, puede usar

[].reverse.call($('li'));
yurakis
fuente
Esto es lo que estaba buscando.
Alexander Dixon
5

Necesitaba hacer un reverso en $ .cada uno, así que usé la idea de Vinay:

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

funcionó bien, gracias

finklez
fuente
Esto no está bien; Esto debería ser $.each(collection.reverse(), ...).
Sophie Alpert
@Ben Alpert: su comentario es defectuoso porque la colección no es una verdadera matriz
vsync
4

No puede iterar hacia atrás con jQuery en cada función, pero aún puede aprovechar la sintaxis de jQuery.

Intenta lo siguiente:

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

He encontrado Array.prototype.reversesin éxito con los objetos, así que hice una nueva función jQuery para usar como alternativa: jQuery.eachBack(). Se repite como lo jQuery.each()haría normalmente y almacena cada clave en una matriz. Luego invierte esa matriz y realiza la devolución de llamada en la matriz / objeto original en el orden de las teclas invertidas.

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

Creo que necesitas

.parentsUntill()
Jimmy M
fuente
1
¿Por qué piensas eso? ¿Y cómo lo usarías?
Bergi
-2

También puedes probar

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