当我运行此脚本时,页面会不断加载并最终冻结。这是因为每次创建元素时,都会调用主DOMContentLoaded侦听器吗?

如果是这样,我如何才能停止这种递归行为,而仅将一个节点添加到每个现有节点中?

//Waits for page to load
document.addEventListener('DOMContentLoaded', function() {

  //Get all elements
    var items = document.getElementsByTagName("*");

    //Loop through entire DOM
    for (var i = 0; i < items.length; i++) {

        //If it is not a text node
        if (!(items[i].nodeType == 3)){

          //Create a div
          var newDiv = document.createElement("div");

          //Add div to current object
          items[i].appendChild(newDiv);
        }

    }
});

最佳答案

这是因为items引用了“活动列表”。这意味着,如果DOM的任何更新与原始选择器匹配,它们都将反映在列表中。

因为要附加div,并且选择器选择所有元素,所以它会添加到列表中,将所有后续成员推入索引,因此迭代将继续。

为了避免这种情况,请在进行迭代之前为集合创建一个非活动副本。

var items = Array.from(document.getElementsByTagName("*"));




仅供参考,可以删除if (!(items[i].nodeType == 3)){,因为getElementsByTagName永远不会返回文本节点。

如果您支持非常老的IE版本,则可能需要检查.nodeType === 1,因为其中一些老版本在使用"*"时包含注释节点。



最后,您可以使用现代功能对此进行一些整理。

document.addEventListener('DOMContentLoaded', () => {
    for (const el of [...document.getElementsByTagName("*")]) {
      var newDiv = el.appendChild(document.createElement("div"));

      // Work with newDiv
    }
});

关于javascript - document.createElement是否继续触发DOMContentLoaded事件监听器?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42321093/

10-09 18:37