Javascript: Как перебрать ВСЕ элементы DOM на странице?

156

Я пытаюсь перебрать ВСЕ элементы на странице, поэтому я хочу проверить каждый элемент, который существует на этой странице, на наличие специального класса.

Итак, как мне сказать, что я хочу проверить КАЖДЫЙ элемент?

Флориан Мюллер
источник
1
Вы уверены, что хотите пройтись по каждому элементу самостоятельно? почему бы не использовать jquery и селекторы для захвата элементов этого класса?
НГ.
Разве нет метода document.getElementsByTagName?
SuperJedi224
* TL; DR: Для видимых элементов используйте:document.body.getElementsByTagName('*')
Эндрю
Повторите с:for (... of ...) { }
Андрей

Ответы:

252

Вы можете передать a, *чтобы getElementsByTagName()он возвращал все элементы на странице:

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

for (var i=0, max=all.length; i < max; i++) {
     // Do something with the element here
}

Обратите внимание, что вы можете использовать querySelectorAll(), если он доступен (IE9 +, CSS в IE8), чтобы просто находить элементы с определенным классом.

if (document.querySelectorAll)
    var clsElements = document.querySelectorAll(".mySpeshalClass");
else
    // loop through all elements instead

Это, безусловно, ускорит дело для современных браузеров.


Браузеры теперь поддерживают foreach на NodeList . Это означает, что вы можете напрямую зацикливать элементы вместо того, чтобы писать свой собственный цикл for.

document.querySelectorAll('*').forEach(function(node) {
    // Do whatever you want with the node object.
});

Примечание по эффективности - сделайте все возможное, чтобы охватить то, что вы ищете. Универсальный селектор может вернуть много узлов в зависимости от сложности страницы. Даже если вам нужно просмотреть все, что кто-то может увидеть, это означает, что вы можете использовать 'body *'в качестве селектора, чтобы вырезать весь headконтент.

Энди Э
источник
2
Этот метод кажется очень хорошим, но как я могу выбрать элемент в верхнем методе? Я получил только индекс «я»?
Флориан Мюллер
2
@Florian: точно так же, как если бы вы обращались к элементу массива, вы бы получили all[i]текущий элемент.
Энди Э
2
Как выделить элемент в боковой петле?
Debiprasad
2
@JesseAldridge: просто сила привычки / хорошей практики. Избегание поиска свойств на каждой итерации обычно является микрооптимизацией, но написать ее не особенно сложно, поэтому я просто делаю это естественно.
Энди Э
2
@Jonathan getElementsByClassName()имеет худшую поддержку, чем querySelectorAll()(первая не поддерживается в IE 8). ОП четко заявил, что он хочет перебрать все элементы на странице, для которых я дал ему решение и предложил альтернативу. Я не уверен, в чем проблема с этим ;-).
Энди Э
39

Искал же. Ну, не совсем так. Я только хотел перечислить все узлы DOM.

var currentNode,
    ni = document.createNodeIterator(document.documentElement, NodeFilter.SHOW_ELEMENT);

while(currentNode = ni.nextNode()) {
    console.log(currentNode.nodeName);
}

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

var currentNode,
    ni = document.createNodeIterator(
                     document.documentElement, 
                     NodeFilter.SHOW_ELEMENT,
                     function(node){
                         return node.classList.contains('toggleable') ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
                     }
         );

while(currentNode = ni.nextNode()) {
    console.log(currentNode.nodeName);
}

Нашел решение на MDN

традиционный
источник
никогда не видел document.ceeateNodeIterator. Интересно, что принесет JS;)
Флориан Мюллер,
2
Крутая особенность этого заключается в том, что nodeiterator также просматривает узлы в порядке их появления в html. Интересно, могут ли некоторые из них document.body.getElementsByTagName('*')вернуть узлы в зашифрованном порядке.
Гражданское
Вау, это на самом деле хорошо поддерживается!
rogerdpack
15

Как всегда, лучшим решением является использование рекурсии:

loop(document);
function loop(node){
    // do some thing with the node here
    var nodes = node.childNodes;
    for (var i = 0; i <nodes.length; i++){
        if(!nodes[i]){
            continue;
        }

        if(nodes[i].childNodes.length > 0){
            loop(nodes[i]);
        }
    }
}

В отличие от других предложений, это решение не требует создания массива для всех узлов, так что его больше света на память. Что еще более важно, он находит больше результатов. Я не уверен, каковы эти результаты, но при тестировании на Chrome он обнаруживает примерно на 50% больше узлов по сравнению сdocument.getElementsByTagName("*");

Илья Газман
источник
19
Лучшее время для использования рекурсии - лучшее время для использования рекурсии.
Адамлив
8
«Он находит примерно на 50% больше узлов по сравнению с document.getElementsByTagName("*");» - да, он найдет текстовые узлы и узлы комментариев, а также узлы элементов . Поскольку ОП просто спрашивал об элементах, это не нужно.
Пол Д. Уэйт
1
Это может быть легче на память. В зависимости от того, сколько вы делаете на каждом уровне рекурсии, вы можете создать очень большой стек вызовов к тому времени, как доберетесь до сути. A NodeListпросто ссылается на Nodes, которые уже встроены в вашу DOM, так что это не так тяжело, как вы можете себе представить. Кто-то, кто знает больше, может взвесить, но я думаю, что это просто эталонный размер памяти, поэтому 8 байтов на узел.
Джош из Карибу
9

Вот еще один пример того, как вы можете перебрать документ или элемент:

function getNodeList(elem){
var l=new Array(elem),c=1,ret=new Array();
//This first loop will loop until the count var is stable//
for(var r=0;r<c;r++){
    //This loop will loop thru the child element list//
    for(var z=0;z<l[r].childNodes.length;z++){

         //Push the element to the return array.
        ret.push(l[r].childNodes[z]);

        if(l[r].childNodes[z].childNodes[0]){
            l.push(l[r].childNodes[z]);c++;
        }//IF           
    }//FOR
}//FOR
return ret;
}
Juggernogger93
источник
4

Для тех, кто использует Jquery

$("*").each(function(i,e){console.log(i+' '+e)});
Матас Вайткявичюс
источник
3

Энди Э. дал хороший ответ.

Я хотел бы добавить, что если вы хотите выбрать все дочерние элементы в каком-то специальном селекторе (эта необходимость недавно произошла со мной), вы можете применить метод "getElementsByTagName ()" к любому нужному объекту DOM.

Например, мне нужно было просто проанализировать «визуальную» часть веб-страницы, поэтому я просто сделал это

var visualDomElts = document.body.getElementsByTagName('*');

Это никогда не будет принимать во внимание главную роль.

Korvus
источник
Превосходно! , , ,
Андрей
2

по этой ссылке
javascript reference

<html>
<head>
<title>A Simple Page</title>
<script language="JavaScript">
<!--
function findhead1()
{
    var tag, tags;
    // or you can use var allElem=document.all; and loop on it
    tags = "The tags in the page are:"
    for(i = 0; i < document.all.length; i++)
    {
        tag = document.all(i).tagName;
        tags = tags + "\r" + tag;
    }
    document.write(tags);
}

//  -->
</script>
</head>
<body onload="findhead1()">
<h1>Heading One</h1>
</body>
</html>

UPDATE: EDIT

так как мой последний ответ я нашел лучшее, более простое решение

function search(tableEvent)
    {
        clearResults()

        document.getElementById('loading').style.display = 'block';

        var params = 'formAction=SearchStocks';

        var elemArray = document.mainForm.elements;
        for (var i = 0; i < elemArray.length;i++)
        {
            var element = elemArray[i];

            var elementName= element.name;
            if(elementName=='formAction')
                continue;
            params += '&' + elementName+'='+ encodeURIComponent(element.value);

        }

        params += '&tableEvent=' + tableEvent;


        createXmlHttpObject();

        sendRequestPost(http_request,'Controller',false,params);

        prepareUpdateTableContents();//function js to handle the response out of scope for this question

    }
Shareef
источник
согласно этому обсуждению ТАК , document.allне рекомендуется в пользу document.getElementBy*.
thejoshwolfe
@thejoshwolfe спасибо, что вы думаете о моем решении socond, которое я обновил
shareef
0

использование *

var allElem = document.getElementsByTagName("*");
for (var i = 0; i < allElem.length; i++) {
    // Do something with all element here
}
Джеки Вонг
источник
0

я думаю это очень быстро

document.querySelectorAll('body,body *').forEach(function(e) {
защищать косатку
источник
0

Получение всех элементов с помощью var all = document.getElementsByTagName("*"); for (var i=0, max=all.length; i < max; i++);нормально, если вам нужно проверить каждый элемент, но приведет к проверке или циклу повторяющихся элементов или текста.

Ниже приведена рекурсивная реализация, которая проверяет или зацикливает каждый элемент всех элементов DOM только один раз и добавляет:

(Авторы @George Reith за свой рекурсивный ответ здесь: сопоставьте HTML с JSON )

function mapDOMCheck(html_string, json) {
  treeObject = {}

  dom = new jsdom.JSDOM(html_string) // use jsdom because DOMParser does not provide client-side Window for element access
  document = dom.window.document
  element = document.querySelector('html')

  // Recurse and loop through DOM elements only once
  function treeHTML(element, object) {
    var nodeList = element.childNodes;

    if (nodeList != null) {
      if (nodeList.length) {
        object[element.nodeName] = []; // IMPT: empty [] array for parent node to push non-text recursivable elements (see below)

        for (var i = 0; i < nodeList.length; i++) {
          console.log("nodeName", nodeList[i].nodeName);

          if (nodeList[i].nodeType == 3) { // if child node is **final base-case** text node
            console.log("nodeValue", nodeList[i].nodeValue);
          } else { // else
            object[element.nodeName].push({}); // push {} into empty [] array where {} for recursivable elements
            treeHTML(nodeList[i], object[element.nodeName][object[element.nodeName].length - 1]);
          }
        }
      }
    }
  }

  treeHTML(element, treeObject);

}
И Сян Чонг
источник
-1

Вы можете попробовать с document.getElementsByClassName('special_class');

Джимиш Гамит
источник
4
Правильный метод, getElementsByClassName()и он не поддерживается Internet Explorer до версии 9.
Энди Э,