2017-02-18 2 views
1

Когда я запускаю этот скрипт, страница постоянно загружается и в конечном итоге зависает. Это потому, что каждый раз, когда я создаю элемент, вызывается главный DOMContentLoaded прослушиватель?Поддерживает ли document.createElement запуск прослушивателя событий 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); 
     } 

    } 
}); 

ответ

1

Это потому, что items ссылается на «живой список». Это означает, что любые обновления DOM будут отображаться в вашем списке, если они соответствуют исходному селектору.

Поскольку вы добавляете div, и ваш селектор выбирает все элементы, он добавляется в список, нажимая на каждый последующий элемент индекс, и поэтому итерация продолжается.

Чтобы избежать этого, сделайте неживую копию коллекции перед повторением.

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

И FYI, то 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 
    } 
}); 
+0

Вау удивительными, работает отлично! Как работает линия 2? Как он избавился от «живой» проблемы? –

+0

@ ЭрикНелсон: Рад, что это помогло. «Array.from()» - это просто утилита, которая преобразует любой объект, подобный массиву, в фактический массив, который не имеет «живых» характеристик. Синтаксис '[... collection]' аналогичен. Это просто синтаксис литерала массива, но использует синтаксис '...' spread для копирования коллекции в создаваемый массив. –

0

Вы получаете постоянно загрузку страницы, потому что у вас есть это:

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

который возвращает "live" node list - означает список, который может/будет изменяться по мере изменений совпавших элементов. Поскольку ваш селектор предназначен для всего, а затем вы создаете новые элементы, набор согласованных элементов изменяется (он становится больше). Который, в свою очередь, приводит к изменению длины списка узлов, что ведет к запуску вашего цикла.

Вы не должны пытаться соответствовать всем элементам или вы должны использовать другой метод для получения элементов, которые не возвращают список живого узла, как querySelectoAll()