วิธีการวนซ้ำอย่างถูกต้องผ่าน getElementsByClassName


108

ฉันเป็นมือใหม่ Javascript

ฉันกำลังเข้าสู่หน้าเว็บผ่านทางwindow.onloadฉันต้องหาองค์ประกอบจำนวนมากตามชื่อคลาส ( slide) และแจกจ่ายใหม่เป็นโหนดต่างๆตามตรรกะบางอย่าง ฉันมีฟังก์ชันDistribute(element)ที่รับองค์ประกอบเป็นอินพุตและทำการกระจาย ฉันต้องการทำสิ่งนี้ (ตามที่อธิบายไว้ที่นี่หรือที่นี่ ):

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

อย่างไรก็ตามสิ่งนี้ไม่ได้ทำเวทมนตร์ให้ฉันเพราะgetElementsByClassNameไม่ได้ส่งคืนอาร์เรย์ แต่ a NodeListซึ่งก็คือ ...

... นี่คือการคาดเดาของฉัน ...

... กำลังเปลี่ยนแปลงภายในฟังก์ชันDistribute(ทรี DOM กำลังถูกเปลี่ยนแปลงภายในฟังก์ชันนี้และการโคลนโหนดบางโหนดจะเกิดขึ้น) For-eachโครงสร้างลูปก็ไม่ช่วยเช่นกัน

การกระทำของสไลด์ตัวแปรนั้นไม่สามารถกำหนดได้จริง ๆ ทุกครั้งที่การทำซ้ำจะเปลี่ยนความยาวและลำดับขององค์ประกอบอย่างรุนแรง

วิธีที่ถูกต้องในการวนซ้ำผ่าน NodeList ในกรณีของฉันคืออะไร? ฉันกำลังคิดเกี่ยวกับการเติมอาร์เรย์ชั่วคราว แต่ไม่แน่ใจว่าจะทำอย่างไร ...

แก้ไข:

ความจริงที่สำคัญฉันลืมที่จะพูดถึงก็คือว่ามีอาจจะเป็นหนึ่งสไลด์ภายในอื่นนี้เป็นจริงสิ่งที่เปลี่ยนแปลงslidesตัวแปรที่ผมได้พบเพียงแค่ออกขอบคุณให้กับผู้ใช้Alohci

วิธีแก้ปัญหาสำหรับฉันคือการโคลนแต่ละองค์ประกอบลงในอาร์เรย์ก่อนและส่งอาร์เรย์ทีละรายการไปในDistribute()ภายหลัง


3
นี่เป็นวิธีที่ทำได้จริง ๆ ดังนั้นคุณต้องยุ่งอย่างอื่น!
adeneo

Distribute()ฟังก์ชั่นคือการที่ยาวและซับซ้อนที่จะคัดลอกที่นี่ แต่ผมมั่นใจว่าผมเปลี่ยนภายในโครงสร้าง DOM, นอกจากนี้ผมยังทำซ้ำ (โคลน) องค์ประกอบที่มี เมื่อฉันแก้ไขข้อบกพร่องฉันสามารถเห็นตัวแปรslidesเปลี่ยนแปลงทุกครั้งที่ส่งผ่านเข้าไปข้างใน
Kupto

จะไม่เปลี่ยนแปลงเว้นแต่คุณจะเปลี่ยนที่ใดที่หนึ่งจริงๆ
adeneo

5
ฉันเชื่อว่าgetElementsByClassName()จะส่งคืนสดnodeListดังนั้นเมื่อองค์ประกอบที่มีคลาสนั้นจะถูกเพิ่มความยาวของส่วนnodeListที่คุณกำลังทำการเปลี่ยนแปลงซ้ำ
เดวิดบอกว่าคืนสถานะโมนิกา

2
@ Kupto- การวนซ้ำในทางกลับกันมักจะแก้ปัญหาประเภทนี้โดยที่ฟังก์ชัน Distribute จะลบหรือย้ายองค์ประกอบเพื่อไม่ให้ตรงกับการเรียก getElementsByClassName อีกต่อไปด้วยเหตุผลที่ David Thomas ให้ไว้
Alohci

คำตอบ:


136

ตาม MDN วิธีการดึงข้อมูลจาก a NodeListคือ:

nodeItem = nodeList.item(index)

ดังนั้น:

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

ฉันไม่ได้ลองทำด้วยตัวเอง ( forลูปปกติใช้ได้ผลกับฉันมาตลอด) แต่ลองดูสิ


นี่เป็นวิธีแก้ปัญหาที่ถูกต้องเว้นแต่คุณจะพยายามค้นหาและเปลี่ยนองค์ประกอบที่มีคลาสเดียวกันและอยู่ภายในซึ่งกันและกัน ฉันอธิบายวิธีแก้ปัญหาในการแก้ไขคำถามของฉัน
Kupto

แน่นอนว่าไม่ได้คำนึงถึงเรื่องนี้
Albert Xing

เหตุใดจึงเป็นเช่นนี้ถ้าฉันอาจถาม เพราะเหตุใดจึงไม่ได้ดำเนินการเพื่อให้คุณสามารถที่จะย้ำกว่าโหนดเช่นนี้for(var el in document.getElementsByClassName("foo")){}?
Nearoo

3
for ... ofช่วยให้คุณสามารถย้ำกว่า NodeList for (slide of slides) Distribute(slide)ในขณะนี้เป็นใน การรองรับเบราว์เซอร์นั้นไม่ดี แต่ถ้าคุณกำลังแสดงผลfor ... ofจะถูกแปลง แต่NodeList.forEachจะไม่ทำเช่นนั้น
Mr5o1

74

หากคุณใช้ querySelectorAll ใหม่คุณสามารถเรียก forEach ได้โดยตรง

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

ตามความคิดเห็นด้านล่าง. nodeLists ไม่มีฟังก์ชัน forEach

หากใช้สิ่งนี้กับ babel คุณสามารถเพิ่มได้Array.fromและจะแปลงรายการที่ไม่ใช่โหนดเป็นอาร์เรย์ forEach Array.fromไม่ทำงานโดยกำเนิดในเบราว์เซอร์ด้านล่างและรวมถึง IE 11

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

เมื่อคืนที่ผ่านมาฉันได้ค้นพบวิธีอื่นในการจัดการรายการโหนดที่ไม่มี forEach

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

รองรับเบราว์เซอร์สำหรับ [... ]

แสดงเป็นรายการโหนด

แสดงเป็นรายการโหนด

แสดงเป็น Array

แสดงเป็น Array


4
Gotcha นี่คือ nodeLists ไม่มีฟังก์ชัน forEach ในทุกเบราว์เซอร์ หากคุณยินดีที่จะให้คนจรจัดกับต้นแบบมันง่ายพอที่จะทำ:if ( !NodeList.prototype.forEach ) {NodeList.prototype.forEach = Array.prototype.forEach;}
joshcanhelp

ทางออกที่สวยงามหากฉันรวมคำตอบของคุณกับความคิดเห็นจาก @joshcanhelp ขอบคุณ :) แน่นอนว่าสิ่งนี้จะนำไปสู่ความได้เปรียบของสายที่มีหลายลูปเท่านั้น
yarwest

1
คุณควรหลีกเลี่ยงสิ่งนี้เนื่องจากอาจใช้ไม่ได้กับทุกเบราว์เซอร์ นี่เป็นวิธีแก้ปัญหาง่ายๆที่ฉันใช้และดูเหมือนว่าจะทำงานได้อย่างสมบูรณ์ทุกที่: css-tricks.com/snippets/javascript/…
tixastronauta

ฉันคิดว่าคุณหมายถึง[...document.getElementsByClassName('.edit')].forEach(function(button) {
wp-overwatch.com

@ wp-overwatch.com ไม่จำเป็นต้องใช้ dot ใน classname เวอร์ชันที่ถูกต้องควรเป็น:[...document.getElementsByClassName('edit')].forEach(function(button) {
MXT

11

คุณสามารถใช้วิธีอาร์เรย์ได้ตลอดเวลา:

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

คำตอบที่ดีและสวยงามขอบคุณมาก!
Olga Farber

2
แจกจ่ายคืออะไร?
lesolorzanov

7

ผมทำตามAlohcinodeListข้อเสนอแนะของการวนลูปในสิ่งที่ตรงกันข้ามเพราะมันสด นี่คือสิ่งที่ฉันทำเพื่อคนที่อยากรู้อยากเห็น ...

  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

ฉันมีปัญหาคล้ายกันกับการทำซ้ำและฉันมาที่นี่ อาจมีคนอื่นกำลังทำผิดแบบเดียวกับที่ฉันทำ

ในกรณีของฉันตัวเลือกไม่ใช่ปัญหาเลย ปัญหาคือฉันทำให้โค้ดจาวาสคริปต์สับสน: ฉันมีลูปและซับลูป subloop ยังใช้iเป็นตัวนับแทนjดังนั้นเนื่องจาก subloop ถูกแทนที่ค่าของiลูปหลักอันนี้จึงไม่เคยไปถึงการวนซ้ำครั้งที่สอง

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

        };

    };
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.