使用JavaScript从每个元素中删除隐藏的类

时间:2019-02-19 20:06:39

标签: javascript arrays

我正在尝试使用JavaScript单击以从元素中删除所有隐藏的类。这是我用来尝试执行此操作的伪代码:

    <style>
    .hidden {display:none;}
    </style>
    

    <div>Value 1</div>
    <div class="hidden">Value 2</div>
    <div class="hidden">Value 3</div>
    <div class="hidden">Value 4</div>
    
    
    <button onclick="removeHidden()">Show All</button>
    
    
    <script>
    function removeHidden()
    {
        var hidden = document.getElementsByClassName("hidden");
        for(var i=0; i<hidden.length; i++)
        {
            hidden[i].classList.remove("hidden");
        }
    }
    </script>

单击按钮时,我希望所有“隐藏”类都将被删除,但是奇怪的是,它从第二个div和第四个div中删除了隐藏的类,但跳过了第三个。

我得到的结果是:

Value 1
Value 2
Value 4

有人知道为什么那是因为我真的不明白这一点吗?

我也尝试了这段代码,但结果相同:

var els = document.getElementsByClassName("hidden");

Array.prototype.forEach.call(els, function(el) {
    el.ClassList.remove("hidden");
});

4 个答案:

答案 0 :(得分:5)

问题是getElementsByClassName()返回一个"live" node list,这是一个列表,只要您引用该列表,它就会更新。这样可以确保您始终获得最新的元素引用。这是一个昂贵的构造,实际上仅在需要时用于少数用例。

每次您的代码都引用hidden变量,将重新扫描DOM以查找具有hidden类的元素,并在您开始删除该类后,将其长度清单中的清单减少了一个。正是由于length的这种变化,一项被跳过了。

要在此处正确使用getElementsByClassName(),请先从最后一个元素中删除该类,然后逐步返回第一个元素。这样可以确保随着节点列表长度的缩短,您不会跳过任何节点。

<style>
    .hidden {display:none;}
</style>
    
    <div>Value 1</div>
    <div class="hidden">Value 2</div>
    <div class="hidden">Value 3</div>
    <div class="hidden">Value 4</div>
    
    
    <button onclick="removeHidden()">Show All</button>
          
    <script>
    function removeHidden()
    {
        var hidden = document.getElementsByClassName("hidden");
        for(var i = hidden.length-1; i > -1; i--)
        {
            hidden[i].classList.remove("hidden");
        }
    }
    </script>

但是,由于活动节点列表会导致性能下降,因此通常不要使用它们。而是使用静态节点列表,您可以使用更现代,更灵活的.querySelectorAll()获得该列表。另外,如果我们将.querySelectorAll()返回的静态节点列表转换为Array,则可以使用Array API通过.forEach()对其进行迭代,从而无需索引器。

<style>
    .hidden {display:none;}
</style>
    

    <div>Value 1</div>
    <div class="hidden">Value 2</div>
    <div class="hidden">Value 3</div>
    <div class="hidden">Value 4</div>        
    
    <button onclick="removeHidden()">Show All</button>
            
    <script>
    function removeHidden()
    {
        // Get all the elements that match the selector into an Array
        var hidden = Array.prototype.slice.call(document.querySelectorAll(".hidden"));
        
        // Now we can loop using the Array API
        hidden.forEach(function(item){
            item.classList.remove("hidden");
        });
    }
    </script>

答案 1 :(得分:2)

您可以使用querySelectorAllgetElementsByClassName的问题在于它生成的列表是dynamic。这意味着如果对change进行了一些DOM,则instantly反映在list中,因为无论何时访问列表,都会扫描DOM以提供列表。因此,在循环中,classes are removed与列表中的length一一对应,而循环中使用的列表grew shorteri<hidden.lengthquerySelectorAll提供了static list从而提供了正确的输出。

function removeHidden() {
  var hidden = document.querySelectorAll(".hidden");
  for (var i = 0; i < hidden.length; i++) {
    hidden[i].classList.remove("hidden");
  }

}
.hidden {
  display: none;
}
<div>Value 1</div>
<div class="hidden">Value 2</div>
<div class="hidden">Value 3</div>
<div class="hidden">Value 4</div>


<button onclick="removeHidden()">Show All</button>

答案 2 :(得分:1)

原因是您要迭代的列表是“实时列表”。这意味着它始终反映DOM的当前状态。这样,当您使用该类从DOM中删除元素时,该元素也会从列表中删除。

删除列表后,将从该点开始重新编制索引,这意味着当前迭代现在指向 next 元素。递增i++后,您将跳过该元素,然后移至下一个元素,该元素以前是前面的两个元素。在您遍历列表时,此操作继续进行。

要解决此问题,请从列表末尾开始迭代,或使用非活动列表进行迭代。

答案 3 :(得分:0)

改为使用var hidden = document.querySelectorAll(".hidden")

编辑:正如Ziggy Wiggy解释的那样,这是因为您遍历DOM元素列表,一旦删除一个,其余的元素实质上就被“移位”或向下索引一个位置。因此,当您遍历值2并将其删除时,值3成为列表中的第一个元素,并且您已经对其进行了遍历,因此循环跳过了值3并转到了值4。为避免这种情况,querySelector种提供了一种DOM元素的快照。

工作片段:

<style>
  .hidden {
    display: none;
  }
</style>


<div>Value 1</div>
<div class="hidden">Value 2</div>
<div class="hidden">Value 3</div>
<div class="hidden">Value 4</div>


<button onclick="removeHidden()">Show All</button>


<script>
  function removeHidden() {
    var hidden = document.querySelectorAll(".hidden");
    for (var i = 0; i < hidden.length; i++) {
      hidden[i].classList.remove("hidden");
    }
  }
</script>