JQuery .each () mundur

442

Saya menggunakan JQuery untuk memilih beberapa elemen pada halaman dan kemudian memindahkannya di DOM. Masalah yang saya alami adalah saya harus memilih semua elemen dalam urutan terbalik yang secara alami ingin dipilih oleh JQuery. Sebagai contoh:

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

Saya ingin memilih semua item li dan menggunakan perintah .each () pada mereka tetapi saya ingin memulai dengan Item 5, lalu Item 4 dll. Apakah ini mungkin?

Jack Mills
sumber

Jawaban:

681
$($("li").get().reverse()).each(function() { /* ... */ });
Joe Chung
sumber
10
Harus penting untuk dicatat bahwa indeks tidak terbalik, jadi jika Anda hanya ingin melakukan tiga terakhir, misalnya, Anda tidak dapat mengharapkan <li>Item 5</li>untuk memiliki indeks 0.
pathfinder
8
ke David Andres: mungkin Anda lupa menambahkan $ () sebelum li. Saya melakukan kesalahan ini dan menerima "fungsi yang tidak jelas".
Michal - wereda-net
2
@ Davidvid: Anda melewatkan .get()yang mengubah jQuery wrap array menjadi JS array biasa. Array JS memiliki .reverse().
stackular
1
Perhatian: Array.reverse()keduanya memodifikasi array di tempat dan mengembalikan array yang terbalik. Jadi solusi ini sebenarnya bergantung pada $ (). Get () mengembalikan array baru, dan bukan referensi ke beberapa jQuery internal atau array DOM. Mungkin taruhan yang aman dalam batas-batas contoh ini. Peringatan Coder.
Bob Stein
404

Saya hadir dengan cara terbersih yang pernah ada, dalam bentuk plugin jquery terkecil di dunia:

jQuery.fn.reverse = [].reverse;

Pemakaian:

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

-Semua kredit untuk Michael Geary dalam posnya di sini: http://www.mail-archive.com/[email protected]/msg04261.html

Waldo Hampton
sumber
Ok, saya setuju itu keren, tapi mengapa itu berhasil? Anda menyalin (secara longgar) Array.prototype.reverse ke jQuery.prototype.reverse, dan ketika dipanggil thisobjek memiliki sifat numerik dan properti panjang, jadi javascript dapat mengindeks dan dapat menerapkan fungsi array ke instance jQuery?
mlhDev
5
Harus penting untuk dicatat bahwa indeks tidak terbalik, jadi jika Anda hanya ingin melakukan tiga terakhir, misalnya, Anda tidak dapat mengharapkan <li>Item 5</li>untuk memiliki indeks 0.
pathfinder
1
@ Matius - Ya, Anda memahaminya dengan benar. Kode yang memang menyalin referensi untuk Array.prototype.reverseke jQuery.prototype.reverse. Banyak metode array JavaScript akan berfungsi dengan baik pada objek apa pun yang terlihat cukup seperti array - yaitu jika objek memiliki .lengthdan properti indeks numerik. reversetidak bergantung pada beberapa representasi internal array; ia mengakses array menggunakan normal .length, [0], [1]dll seperti kode array yang kau tulis sendiri.
Michael Geary
8
Bukankah boros untuk membuat Array baru hanya untuk mendapatkan reversemetodenya? Bukankah lebih cepat hanya menyalin referensi ke fungsi Array.prototype.reverse, misalnya jQuery.fn.reverse = Array.prototype.reverse;? Tidak sesingkat dan "pintar", tetapi lebih efisien? Memang ini mungkin tidak akan terlihat di browser cepat kilat hari ini, tapi masih ...
zachelrath
3
@zachelrath Ya, saya tidak bisa mendapatkan pemisahan antara hasil, lagi. Sepertinya 20% itu hanya kebetulan. Ingat, Anda hanya mengatur fungsi sekali, jadi instantiasi hanya terjadi sekali, dari sana fungsi diatur.
Sandy Gifford
64

Anda dapat melakukan

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

diikuti oleh

$(selector).reverse().each(...) 
Vinay Sajip
sumber
14
Pendekatan ini pada awalnya diusulkan oleh John Resig (pengembang jQuery) di milis jQuery .
Chris Shouts
20

Berikut beberapa opsi untuk ini:

Pertama : tanpa 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 di sini

... dan dengan jQuery:

Anda bisa menggunakan ini:

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

Demo di sini

Cara lain , menggunakan jQuery juga dengan terbalik adalah:

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

Demo ini di sini .

Satu lagi alternatif adalah dengan menggunakan length(jumlah elemen yang cocok dengan pemilih itu) dan turun dari sana menggunakan indexsetiap iterasi. Maka Anda dapat menggunakan ini:

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

Demo ini di sini

Satu lagi , jenis yang terkait dengan yang di atas:

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

Demo di sini

Sergio
sumber
14

Saya lebih suka membuat reverse plug-in misalnya

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

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

Penggunaan misalnya:

$('#product-panel > div').reverse(function(i, e) {
    alert(i);
    alert(e);
});
James Westgate
sumber
Saya suka ide / kode ini juga, tetapi tidak mengembalikan objek yang dapat dirantai (yang dibalik) seperti jawaban dengan suara lebih tinggi :) Tetap, pasti metode yang bagus untuk pengaturannya
Ian
Kamu benar. Tidak bisa diterbangkan jadi bukan plugin yang valid. Namun telah sedikit meningkatkan kode, memindahkan decrementer ke dalam kondisi.
James Westgate
8

Jika Anda tidak ingin menyimpan metode ke jQuery.fn, Anda dapat menggunakannya

[].reverse.call($('li'));
yuraki
sumber
Ini yang saya cari.
Alexander Dixon
5

Diperlukan untuk melakukan pembalikan pada $ .each jadi saya menggunakan ide Vinay:

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

bekerja dengan baik, terima kasih

finklez
sumber
Ini tidak benar; ini seharusnya $.each(collection.reverse(), ...).
Sophie Alpert
@ Ben Alpert - komentar Anda cacat, karena koleksi bukan array yang benar
vsync
4

Anda tidak dapat mengulangi mundur dengan fungsi masing-masing jQuery, tetapi Anda masih dapat memanfaatkan sintaks jQuery.

Coba yang berikut ini:

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

Saya menemukan Array.prototype.reversetidak berhasil dengan benda-benda, jadi saya membuat fungsi jQuery baru untuk digunakan sebagai alternatif: jQuery.eachBack(). Itu berulang seperti biasa jQuery.each(), dan menyimpan setiap kunci ke dalam array. Ini kemudian membalikkan array itu dan melakukan panggilan balik pada array / objek asli dalam urutan kunci terbalik.

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

Saya pikir kamu perlu

.parentsUntill()
Jimmy M.
sumber
1
Mengapa kamu berpikir begitu? Dan bagaimana Anda menggunakannya?
Bergi
-2

Anda juga bisa mencoba

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