Cách lặp lại chính xác thông qua getElementsByClassName


100

Tôi là người mới bắt đầu về Javascript.

Tôi đang truy cập trang web thông qua window.onload, tôi phải tìm các phần tử theo tên lớp của chúng ( slide) và phân phối lại chúng thành các nút khác nhau dựa trên một số logic. Tôi có chức năng Distribute(element)lấy một phần tử làm đầu vào và thực hiện phân phối. Tôi muốn làm điều gì đó như thế này (như được nêu, ví dụ ở đây hoặc ở đây ):

var slides = getElementsByClassName("slide");
for(var i = 0; i < slides.length; i++)
{
   Distribute(slides[i]);
}

tuy nhiên điều này không làm điều kỳ diệu đối với tôi, bởi vì getElementsByClassNamekhông thực sự trả về mảng, mà là a NodeList, là ...

... đây là suy đoán của tôi ...

... được thay đổi bên trong chức năng Distribute(cây DOM đang được thay đổi bên trong chức năng này và việc sao chép các nút nhất định sẽ xảy ra). For-eachcấu trúc vòng lặp cũng không giúp ích gì.

Hành động của các slide thay đổi thực sự không xác định, qua mỗi lần lặp lại, nó thay đổi độ dài và thứ tự của các phần tử một cách điên cuồng.

Cách chính xác để lặp qua NodeList trong trường hợp của tôi là gì? Tôi đã nghĩ đến việc lấp đầy một số mảng tạm thời, nhưng không chắc chắn làm thế nào để thực hiện điều đó ...

BIÊN TẬP:

thực tế quan trọng mà tôi quên đề cập là có thể có một slide bên trong một slide khác, đây thực sự là những gì thay đổi slidesbiến mà tôi vừa tìm ra nhờ người dùng Alohci .

Giải pháp cho tôi là sao chép từng phần tử vào một mảng trước và chuyển từng phần tử vào Distribute()sau đó.


3
Đây thực sự là cách để làm điều đó, vì vậy bạn phải làm rối tung một thứ gì đó lên!
adeneo

các Distribute()chức năng là để lâu dài và phức tạp để được sao chép ở đây, nhưng tôi chắc chắn rằng tôi đang thay đổi bên trong cấu trúc DOM, tôi cũng đang sao chép (nhân bản) các yếu tố đó. Khi tôi gỡ lỗi nó, tôi có thể thấy biến slidesthay đổi mỗi khi nó được chuyển vào bên trong.
Kupto

Nó không thay đổi trừ khi bạn thực sự thay đổi nó ở đâu đó.
adeneo

5
Tôi tin rằng điều đó getElementsByClassName()trả về trực tiếp nodeList, vì vậy các phần tử với lớp đó được thêm vào độ dài nodeListmà bạn đang lặp lại các thay đổi.
David nói hãy phục hồi Monica vào

2
@ Kupto- looping ngược lại thường giải quyết loại vấn đề này, trong đó hàm phân phối loại bỏ hoặc di chuyển phần tử để nó không còn khớp với lời gọi getElementsByClassName, vì lý do mà David Thomas đưa ra.
Alohci

Câu trả lời:


130

Theo MDN, cách để lấy một mục từ a NodeListlà:

nodeItem = nodeList.item(index)

Như vậy:

var slides = document.getElementsByClassName("slide");
for (var i = 0; i < slides.length; i++) {
   Distribute(slides.item(i));
}

Tôi chưa thử điều này bản thân mình ( forvòng lặp bình thường luôn hoạt động với tôi), nhưng hãy thử.


Đây là giải pháp phù hợp, trừ khi bạn cố gắng tìm kiếm và thay đổi các phần tử có cùng lớp và nằm trong nhau. Tôi đã giải thích cách giải quyết của mình bằng cách chỉnh sửa câu hỏi của mình.
Kupto

Chắc chắn, không tính đến điều đó.
Albert Xing

Tại sao nó lại theo cách này, nếu tôi có thể hỏi? Tại sao nó không được triển khai để bạn có thể lặp qua các nút như thế này for(var el in document.getElementsByClassName("foo")){}?
Nearoo

3
for ... ofcho phép bạn lặp lại NodeList ngay bây giờ như trong for (slide of slides) Distribute(slide). Hỗ trợ trình duyệt là chắp vá, nhưng nếu bạn đang for ... ofchuyển đổi thì nó sẽ được chuyển đổi, nhưng NodeList.forEachsẽ không.
Mr5o1

67

Nếu bạn sử dụng querySelectorAll mới, bạn có thể gọi trực tiếp forEach.

document.querySelectorAll('.edit').forEach(function(button) {
    // Now do something with my button
});

Theo nhận xét dưới đây. nodeLists không có chức năng forEach.

Nếu sử dụng điều này với babel, bạn có thể thêm Array.fromvà nó sẽ chuyển đổi danh sách không phải nút thành một mảng forEach. Array.fromkhông hoạt động nguyên bản trong các trình duyệt bên dưới và bao gồm cả IE 11.

Array.from(document.querySelectorAll('.edit')).forEach(function(button) {
    // Now do something with my button
});

Tại buổi gặp mặt của chúng ta đêm qua, tôi đã phát hiện ra một cách khác để xử lý danh sách nút không có forEach

[...document.querySelectorAll('.edit')].forEach(function(button) {
    // Now do something with my button
});

Hỗ trợ trình duyệt cho [...]

Hiển thị dưới dạng danh sách nút

Hiển thị dưới dạng danh sách nút

Hiển thị dưới dạng Mảng

Hiển thị dưới dạng Mảng


4
Điều này rất hiểu là nodeLists không có chức năng forEach trong mọi trình duyệt. Nếu bạn sẵn sàng để tinker với nguyên mẫu, nó đủ đơn giản để làm:if ( !NodeList.prototype.forEach ) {NodeList.prototype.forEach = Array.prototype.forEach;}
joshcanhelp

Giải pháp tuyệt vời nếu tôi kết hợp câu trả lời của bạn với nhận xét từ @joshcanhelp. Cảm ơn :) Tất nhiên điều này sẽ chỉ dẫn đến lợi thế dòng với nhiều vòng lặp.
yarwest

1
Bạn nên tránh điều này vì nó có thể không hoạt động trên tất cả các trình duyệt. Đây là một cách giải quyết đơn giản mà tôi sử dụng và dường như hoạt động hoàn hảo ở mọi nơi: css-tricks.com/snippets/javascript/…
tixastronauta 14/02/17

Tôi nghĩ ý bạn là[...document.getElementsByClassName('.edit')].forEach(function(button) {
wp-overwatch.com

@ wp-overwatch.com không cần dấu chấm trong tên lớp. Phiên bản đúng phải là:[...document.getElementsByClassName('edit')].forEach(function(button) {
MXT

11

Bạn luôn có thể sử dụng các phương thức mảng:

var slides = getElementsByClassName("slide");
Array.prototype.forEach.call(slides, function(slide, index) {
    Distribute(slides.item(index));
});

câu trả lời rất hay và đẹp, cảm ơn bạn rất nhiều!
Olga Farber

Phân phối là gì?
lesolorzanov

7

Tôi đã làm theo khuyến nghị của Alohci về việc lặp lại ngược lại vì đó là một buổi biểu diễn trực tiếp nodeList. Đây là những gì tôi đã làm cho những ai tò mò ...

  var activeObjects = documents.getElementsByClassName('active'); // a live nodeList

  //Use a reverse-loop because the array is an active NodeList
  while(activeObjects.length > 0) {
    var lastElem = activePaths[activePaths.length-1]; //select the last element

    //Remove the 'active' class from the element.  
    //This will automatically update the nodeList's length too.
    var className = lastElem.getAttribute('class').replace('active','');
    lastElem.setAttribute('class', className);
  }

1
 <!--something like this--> 
<html>
<body>



<!-- i've used for loop...this pointer takes current element to apply a 
 particular change on it ...other elements take change by else condition 
-->  


<div class="classname" onclick="myFunction(this);">first</div>  
<div class="classname" onclick="myFunction(this);">second</div>


<script>
function myFunction(p) {
 var x = document.getElementsByClassName("classname");
 var i;
 for (i = 0; i < x.length; i++) {
    if(x[i] == p)
    {
x[i].style.background="blue";
    }
    else{
x[i].style.background="red";
    }
}
}


</script>
<!--this script will only work for a class with onclick event but if u want 
to use all class of same name then u can use querySelectorAll() ...-->




var variable_name=document.querySelectorAll('.classname');
for(var i=0;i<variable_name.length;i++){
variable_name[i].(--your option--);
}



 <!--if u like to divide it on some logic apply it inside this for loop 
 using your nodelist-->

</body>
</html>

0

Tôi đã gặp sự cố tương tự với việc lặp lại và tôi đã hạ cánh ở đây. Có thể ai đó khác cũng đang làm sai lầm giống tôi.

Trong trường hợp của tôi, bộ chọn hoàn toàn không phải là vấn đề. Vấn đề là tôi đã làm sai mã javascript: Tôi có một vòng lặp và một vòng lặp con. Vòng lặp con cũng được sử dụng inhư một bộ đếm, thay vì j, vì vòng lặp con đang ghi đè giá trị của ivòng lặp chính, vòng lặp này không bao giờ có đến lần lặp thứ hai.

var dayContainers = document.getElementsByClassName('day-container');
for(var i = 0; i < dayContainers.length; i++) { //loop of length = 2
        var thisDayDiv = dayContainers[i];
        // do whatever

        var inputs = thisDayDiv.getElementsByTagName('input');

        for(var j = 0; j < inputs.length; j++) { //loop of length = 4
            var thisInput = inputs[j];
            // do whatever

        };

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