Як правильно виконати ітерацію через getElementsByClassName


101

Я початківець 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 .

Рішенням для мене було спочатку клонувати кожен елемент у масив, а потім передавати масив ono-by-one Distribute().


3
Це насправді спосіб це зробити, тож ви, мабуть, щось інше зіпсуєте!
adeneo

Distribute()функція є тривалим і складним , щоб скопіювати тут, але я впевнений , що я змінюю структуру DOM всередині, я також тиражування (клонування) елементи там. Коли я налагоджую її, я бачу, як змінна slidesзмінюється кожного разу, коли вона передається всередину.
Купто

Це не змінюється, якщо ви насправді це десь не змінили.
adeneo

5
Я вважаю, що getElementsByClassName()повертає live nodeList, тому як елементи з цим класом додаються зміни довжини, nodeListпротягом якої ви ітераціюєте.
Девід каже, що відновити Моніку

2
@ Kupto-циклічність у зворотному порядку часто вирішує подібну проблему, коли функція Distribute видаляє або переміщує елемент таким чином, що він більше не відповідає виклику getElementsByClassName, з причини, яку дає Девід Томас.
Alohci

Відповіді:


130

Згідно з 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цикл завжди працював у мене), але спробуй.


Це правильне рішення, якщо ви не спробуєте знайти та змінити елементи, що мають однаковий клас і знаходяться один в одному. Я пояснив своє обхідне рішення в редагуванні свого питання.
Купто

Звичайно, не врахував це.
Альберт Сін

Чому це так, якщо я можу запитати? Чому це не реалізовано, щоб ви могли переглядати такі вузли for(var el in document.getElementsByClassName("foo")){}?
Nearoo

3
for ... ofдозволяє переглядати NodeList зараз, як у for (slide of slides) Distribute(slide). Підтримка браузера є нерівномірною, але якщо ви виконуєте транпіляцію, for ... ofце буде перетворено, але NodeList.forEachне буде.
Mr5o1

68

Якщо ви використовуєте новий 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
});

Підтримка браузера для [...]

Показано як список вузлів

Показано як список вузлів

Показано як масив

Показано як масив


4
Зрозуміло, що nodeLists не мають функції forEach у кожному браузері. Якщо ви готові повозитись з прототипами, зробити це досить просто:if ( !NodeList.prototype.forEach ) {NodeList.prototype.forEach = Array.prototype.forEach;}
joshcanhelp

Елегантне рішення, якщо я поєднаю вашу відповідь із коментарем від @joshcanhelp. Дякую :) Звичайно, це призведе лише до переваги лінії з кількома циклами.
найсвіжіший

1
Вам слід уникати цього, оскільки це може працювати не у всіх браузерах. Ось просте обхідне рішення, яке я використовую, і, схоже, чудово працює скрізь: css-tricks.com/snippets/javascript/…
tixastronauta

Думаю, ви мали на увазі[...document.getElementsByClassName('.edit')].forEach(function(button) {
wp-overwatch.com

@ wp-overwatch.com точка не потрібна в назві класу. Правильна версія повинна бути:[...document.getElementsByClassName('edit')].forEach(function(button) {
MXT

11

Ви завжди можете використовувати методи масиву:

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

дуже приємна і гарна відповідь, велике спасибі!
Ольга Фарбер

1
Що таке розповсюдження?
lesolorzanov

7

Я дотримувався рекомендації Alohci щодо циклічного звороту, тому що це живе nodeList. Ось що я зробив для тих, хто цікавиться ...

  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

У мене була подібна проблема з ітерацією, і я приземлився тут. Можливо, хтось інший теж робить ту ж помилку, що і я.

У моєму випадку селектор взагалі не був проблемою. Проблема полягала в тому, що я переплутав код JavaScript: у мене був цикл і підцикл. 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

        };

    };
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.