JQuery .each () ngược


442

Tôi đang sử dụng JQuery để chọn một số thành phần trên một trang và sau đó di chuyển chúng xung quanh trong DOM. Vấn đề tôi gặp phải là tôi cần chọn tất cả các phần tử theo thứ tự ngược lại mà JQuery muốn chọn chúng một cách tự nhiên. Ví dụ:

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

Tôi muốn chọn tất cả các mục li và sử dụng lệnh .each () trên chúng nhưng tôi muốn bắt đầu với Mục 5, sau đó Mục 4, v.v. Điều này có khả thi không?

Câu trả lời:


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

10
Điều quan trọng cần lưu ý là chỉ mục không bị đảo ngược, vì vậy, nếu bạn chỉ muốn thực hiện ba lần cuối, chẳng hạn, bạn không thể mong đợi <li>Item 5</li>có chỉ số là 0.
pathfinder

8
cho David Andres: có thể bạn đã quên thêm $ () trước li. Tôi đã làm sai lầm này và nhận được "func không xác định".
Michal - wereda-net

2
@DavidAndres: Bạn đã bỏ lỡ việc .get()biến mảng được gói jQuery thành một mảng JS thông thường. Mảng JS có .reverse().
xếp chồng

1
Thận trọng: Array.reverse()cả hai sửa đổi mảng tại chỗ và trả về mảng đảo ngược. Vì vậy, giải pháp này thực sự dựa vào $ (). Get () trả về một mảng mới và không tham chiếu đến một số mảng jQuery hoặc DOM nội bộ. Có lẽ là đặt cược an toàn trong giới hạn của ví dụ này. Coder Caveat.
Bob Stein

404

Tôi giới thiệu với bạn cách thức sạch nhất từ ​​trước đến nay, dưới dạng plugin jquery nhỏ nhất thế giới:

jQuery.fn.reverse = [].reverse;

Sử dụng:

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

-Tất cả tín dụng cho Michael Geary trong bài đăng của mình ở đây: http://www.mail-archive.com/discuss@jquery.com/msg04261.html


Ok, tôi đồng ý rằng điều đó thật tuyệt, nhưng tại sao nó lại hoạt động? Bạn đang sao chép (nói một cách lỏng lẻo) Array.prototype.reverse sang jQuery.prototype.reverse và khi nó được gọi thì thisđối tượng có các thuộc tính số và thuộc tính độ dài, vì vậy javascript có thể lập chỉ mục cho nó và có thể áp dụng hàm mảng cho một cá thể jQuery không?
mlhDev

5
Điều quan trọng cần lưu ý là chỉ mục không bị đảo ngược, vì vậy, nếu bạn chỉ muốn thực hiện ba lần cuối, chẳng hạn, bạn không thể mong đợi <li>Item 5</li>có chỉ số là 0.
pathfinder

1
@Matthew - Vâng, bạn hiểu đúng. Mã đó thực sự sao chép một tham chiếu đến Array.prototype.reversehơn jQuery.prototype.reverse. Nhiều phương thức mảng JavaScript sẽ hoạt động tốt trên bất kỳ đối tượng nào trông giống như một mảng - đó là nếu đối tượng có .lengthvà thuộc tính chỉ mục số. reversekhông phụ thuộc vào một số đại diện nội bộ của mảng; nó truy cập vào mảng bằng cách sử dụng bình thường .length, [0], [1], vv chỉ như mã mảng bạn muốn viết cho mình.
Michael Geary

8
Không phải là lãng phí khi khởi tạo một Array mới chỉ để có được reversephương thức của nó sao? Sẽ không nhanh hơn nếu chỉ sao chép qua một tham chiếu đến hàm Array.prototype.reverse, vd jQuery.fn.reverse = Array.prototype.reverse;? Không phải là ngắn và "thông minh", nhưng hiệu quả hơn? Phải thừa nhận rằng điều này có thể sẽ không được chú ý trong các trình duyệt nhanh như chớp ngày nay, nhưng vẫn ...
zachelrath

3
@zachelrath Vâng, tôi không thể có bất kỳ sự tách biệt nào giữa các kết quả nữa. Có vẻ như 20% chỉ là một con sán. Hãy nhớ rằng, bạn chỉ thiết lập chức năng một lần, do đó việc khởi tạo chỉ xảy ra một lần, từ đó chức năng được đặt.
Sandy Gifford

64

Bạn có thể làm

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

theo dõi bởi

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

14
Cách tiếp cận này ban đầu được đề xuất bởi John Resig (nhà phát triển jQuery) trong danh sách gửi thư của jQuery .
Chris hét lên

20

Dưới đây là các tùy chọn khác nhau cho việc này:

Đầu tiên : không có 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 tại đây

... và với jQuery:

Bạn có thể sử dụng điều này:

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

Demo tại đây

Một cách khác , sử dụng jQuery cũng ngược lại là:

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

Bản demo này ở đây .

Một cách khác là sử dụng length(số phần tử khớp với bộ chọn đó) và đi xuống từ đó bằng cách sử dụng indexmỗi lần lặp. Sau đó, bạn có thể sử dụng này:

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

Bản demo này tại đây

Một , nhiều loại liên quan đến một ở trên:

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

Demo tại đây


14

Tôi thích tạo một trình cắm ngược, vd

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

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

Cách sử dụng, vd:

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

Tôi cũng thích ý tưởng / mã này, nhưng nó không trả về một đối tượng có thể xâu chuỗi (bị đảo ngược) như các câu trả lời được bình chọn cao hơn :) Tuy nhiên, chắc chắn là một phương pháp tốt cho cách thiết lập
Ian

Bạn đúng rồi. Không có chuỗi nên không phải là một plugin hợp lệ. Đã cải thiện mã một chút mặc dù, di chuyển decrementer vào điều kiện.
James Westgate

8

Nếu bạn không muốn lưu phương thức vào jQuery.fn, bạn có thể sử dụng

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

Đây là những gì tôi đang tìm kiếm.
Alexander Dixon

5

Cần phải làm ngược lại với $ .each vì vậy tôi đã sử dụng ý tưởng Vinay:

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

làm việc tốt, cảm ơn


Điều này không đúng; điều này chỉ nên được $.each(collection.reverse(), ...).
Sophie Alpert

@Ben Alpert - nhận xét của bạn không hoàn hảo, vì bộ sưu tập không phải là một mảng thực sự
vsync

4

Bạn không thể lặp lại ngược lại với mỗi hàm jQuery, nhưng bạn vẫn có thể tận dụng cú pháp jQuery.

Hãy thử như sau:

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

Tôi thấy Array.prototype.reversekhông thành công với các đối tượng, vì vậy tôi đã tạo một hàm jQuery mới để sử dụng thay thế : jQuery.eachBack(). Nó lặp đi lặp lại như bình thường jQuery.each()và lưu trữ mỗi khóa thành một mảng. Sau đó, nó đảo ngược mảng đó và thực hiện gọi lại trên mảng / đối tượng ban đầu theo thứ tự các phím đảo ngược.

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

Tôi nghĩ bạn cần

.parentsUntill()

1
Tại sao bạn nghĩ rằng? Và bạn sẽ sử dụng nó như thế nào?
Bergi

-2

Bạn cũng có thể thử

var arr = [].reverse.call($('li'))
arr.each(function(){ ... })
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.