Список классов JS не работает полностью в цикле for

#javascript

#javascript

Вопрос:

У меня есть три div, каждый из которых содержит еще один div, которые скрыты классом с именем none . когда я нажимаю кнопку show squares , функция displaySquares должна удалить все классы none, но это не так. lOb.classList возвращает undefined на определенной итерации, и я не знаю почему? Любая помощь будет оценена.

         function displaySquares(x){        
            var dr = document.getElementsByClassName(x),pl=dr.length,i=0;

            for (i; i < pl; i  ) {
                var lOb = dr[i]; 

                if (lOb.classList) { 
                    if (lOb.classList.contains(x)) {
                        lOb.classList.remove(x);
                    }
                } else { //fallback for classList
                    var r = new RegExp("\b"   x  "\b", "g");
                    if (r.test(lOb.className)) {
                        lOb.className = lOb.className.replace(r, "");

                    }
                }
            }
        }  
     .clcn{
        width:130px;
        height:130px;
        background: rgba(0,0,0,0.5);  
        border:1px solid red;
        }
    .clcn2{
        position:absolute;
        width:30px;
        height:30px;
        background: yellow;  
        border:1px solid blue;
        }
    .none{
        display:none;
        }  
 <div  class="clcn">
    <div  class="clcn2 none"></div>
</div>
<div  class="clcn">
    <div  class="clcn2 none"></div>
</div>
<div  class="clcn">
    <div  class="clcn2 none"></div>
</div>
<button  onclick="displaySquares('none');">show squares</button>  

Комментарии:

1. Использование .querySelectorAll вернет статический список, который не будет страдать от проблем live HTMLCollection, описанных ниже. function displaySquares(x){ let dr = document.querySelectorAll('.' x); dr.forEach(element => element.classList.remove(x));}

Ответ №1:

проблема в том, что вы меняете имя элементов на каждой итерации, поэтому

  • на первой итерации у вас есть 3 элемента с классом none и I = 0, так что у вас есть элемент, затем вы удаляете 1, и теперь у вас есть 2
  • на второй итерации у вас есть 2 элемента с классом none и I = 1, так что у вас есть элемент, затем вы удаляете 1, так что теперь у вас есть 1
  • на третьей итерации у вас есть только 1 элемент с классом none в массиве «dr» и I = 2, поэтому у вас нет элемента в индексе 2, у вас есть только один элемент в индексе 1, поэтому dr[2] не определен
  • решение, которое я принял, заключается в том, что я всегда получаю индекс первого элемента 0 и изменяю его
  • причина, по которой это произошло, заключается в том, что dr является ссылкой на dom, поэтому, когда вы меняете dom, вы меняете dr, потому что это просто указатель на ссылку надеюсь, я помог

 function displaySquares(x){        
            var dr = document.getElementsByClassName(x),pl=dr.length,i=0;

            for (i; i < pl; i  ) {
// fix 
                var lOb = dr[0]; 

                if (lOb.classList) { 
                    if (lOb.classList.contains(x)) {
                        lOb.classList.remove(x);
                    }
                } else { //fallback for classList
                    var r = new RegExp("\b"   x  "\b", "g");
                    if (r.test(lOb.className)) {
                        lOb.className = lOb.className.replace(r, "");

                    }
                }
            }
        }  
 .clcn{
        width:130px;
        height:130px;
        background: rgba(0,0,0,0.5);  
        border:1px solid red;
        }
    .clcn2{
        position:absolute;
        width:30px;
        height:30px;
        background: yellow;  
        border:1px solid blue;
        }
    .none{
        display:none;
        }  
 <div  class="clcn">
    <div  class="clcn2 none"></div>
</div>
<div  class="clcn">
    <div  class="clcn2 none"></div>
</div>
<div  class="clcn">
    <div  class="clcn2 none"></div>
</div>
<button  onclick="displaySquares('none');">show squares</button>  

Ответ №2:

Причина в том, что каждый раз, когда вы удаляете имя класса «none» из одного из элементов во время цикла, количество элементов в коллекции html (переменная «dr») изменяется. Итак, он начинается с 3, затем на следующей итерации это 2 и т.д. И поскольку вы увеличиваете «i», вы в основном пропускаете элемент.

Одним из возможных решений было бы использовать цикл while вместо цикла for, чтобы вы просто продолжали цикл, пока не останется никаких элементов.

                 while (dr.length) {
                var lOb = dr[0]; 
                                            
                if (lOb.classList) { 
                    if (lOb.classList.contains(x)) {
                        lOb.classList.remove(x);
                    }
                } else { //fallback for classList
                    var r = new RegExp("\b"   x  "\b", "g");
                    if (r.test(lOb.className)) {
                        lOb.className = lOb.className.replace(r, "");
                                                        
                    }
                }
            }