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?

Respuestas:


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

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


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

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í


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

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


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


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
}

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

-2

Creo que necesitas

.parentsUntill()

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(){ ... })
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.