Javascript: como percorrer todos os elementos DOM em uma página?

156

Estou tentando fazer um loop sobre TODOS os elementos em uma página, então quero verificar todos os elementos que existem nesta página para uma classe especial.

Então, como digo que quero verificar TODOS os elementos?

Florian Müller
fonte
1
tem certeza de que deseja percorrer todos os elementos? por que não usar jquery e seletores para capturar elementos que são dessa classe específica?
NG.
Não existe um método document.getElementsByTagName?
SuperJedi224
* TL; DR: para elementos visíveis apenas, use:document.body.getElementsByTagName('*')
Andrew
Iterar com:for (... of ...) { }
Andrew

Respostas:

252

Você pode passar um *para getElementsByTagName()para que ele retorne todos os elementos em uma página:

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

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

Observe que você pode usar querySelectorAll(), se estiver disponível (IE9 +, CSS no IE8), apenas encontrar elementos com uma classe específica.

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

Isso certamente agilizaria os navegadores modernos.


Os navegadores agora suportam foreach no NodeList . Isso significa que você pode fazer um loop direto dos elementos em vez de escrever seu próprio loop for.

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

Nota de desempenho - Faça o possível para definir o que você está procurando. Um seletor universal pode retornar muitos nós, dependendo da complexidade da página. Mesmo que você precise examinar tudo o que alguém vê, isso significa que você pode usar 'body *'como seletor para cortar todo o headconteúdo.

Andy E
fonte
2
Esse método parece muito bom, mas como posso selecionar um elemento no método superior? Eu só tenho o índice 'i'?
Florian Müller
2
@ Florida: assim como você acessaria um elemento da matriz - all[i]daria o elemento atual.
Andy E
2
Como selecionar o elemento ao lado do loop?
Debiprasad
2
@ JesseAldridge: apenas uma força do hábito / boas práticas. Evitar a pesquisa de propriedades em todas as iterações geralmente é uma micro-otimização, mas não é particularmente mais difícil de escrever e, portanto, faço isso naturalmente.
Andy E
2
@ Jonathan getElementsByClassName()tem um suporte pior do que querySelectorAll()(o primeiro não é suportado no IE 8). O OP afirmou claramente que ele deseja repetir todos os elementos de uma página, para os quais eu dei a solução e ofereci uma alternativa. Não sei ao certo qual é o problema ;-).
Andy E
39

Estava procurando o mesmo. Bem, não exatamente. Eu só queria listar todos os nós do DOM.

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

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

Para obter elementos com uma classe específica, podemos usar a função de filtro.

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);
}

Solução encontrada no MDN

tradicional
fonte
nunca vi document.ceeateNodeIterator. Parece interessante o que novos recursos JS traz;)
Florian Müller
2
Uma característica interessante disso é que o nodeiterator também percorre os nós na ordem em que aparecem no html. Gostaria de saber se alguns dos document.body.getElementsByTagName('*')poderiam retornar os nós em ordem codificada.
Civil
Uau, é realmente bem suportado!
rogerdpack
15

Como sempre, a melhor solução é usar a recursão:

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]);
        }
    }
}

Diferente de outras sugestões, esta solução não exige que você crie uma matriz para todos os nós, portanto, fica mais claro na memória. Mais importante, ele encontra mais resultados. Não sei ao certo quais são esses resultados, mas ao testar no chrome, ele encontra cerca de 50% mais nós em comparação com odocument.getElementsByTagName("*");

Ilya Gazman
fonte
19
O melhor momento para usar a recursão é o melhor momento para usar a recursão.
Adamlive
8
“Ele encontra cerca de 50% mais nós em comparação com document.getElementsByTagName("*");” - sim, encontrará nós de texto e nós de comentários, bem como nós de elementos . Como o OP estava apenas perguntando sobre elementos, isso é desnecessário.
Paul D. Waite
1
Ele pode ser mais leve na memória. Dependendo do quanto você faz em cada nível de recursão, você pode criar uma pilha de chamadas poderosamente grande quando chegar ao fundo. A NodeListé simplesmente fazer referência aos Nodes que já foram criados no seu DOM, portanto não é tão pesado quanto você imagina. Alguém que sabe mais pode pesar, mas acho que é apenas um tamanho de referência de memória, portanto, 8 bytes por nó.
Josh de Qaribou
9

Aqui está outro exemplo de como você pode percorrer um documento ou elemento:

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
fonte
4

Para quem está usando o Jquery

$("*").each(function(i,e){console.log(i+' '+e)});
Matas Vaitkevicius
fonte
3

Andy E. deu uma boa resposta.

Eu acrescentaria que, se você selecionar todos os filhos em algum seletor especial (essa necessidade aconteceu recentemente), você poderá aplicar o método "getElementsByTagName ()" em qualquer objeto DOM que desejar.

Por exemplo, eu precisava apenas analisar parte "visual" da página da Web, então fiz isso

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

Isso nunca levará em consideração a parte principal.

korvus
fonte
Excelente! . . .
Andrew
2

a partir deste link
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

desde a minha última resposta, encontrei uma solução melhor e mais simples

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
fonte
de acordo com esta discussão SO , document.allé desencorajado em favor de document.getElementBy*.
thejoshwolfe
@thejoshwolfe graças O que você acha da minha solução socond i atualizados
shareef
0

Usar *

var allElem = document.getElementsByTagName("*");
for (var i = 0; i < allElem.length; i++) {
    // Do something with all element here
}
Jacky Wong
fonte
0

eu acho que isso é muito rápido

document.querySelectorAll('body,body *').forEach(function(e) {
defender a orca
fonte
0

A obtenção de todos os elementos var all = document.getElementsByTagName("*"); for (var i=0, max=all.length; i < max; i++);está ok se você precisar verificar todos os elementos, mas resultará na verificação ou loop de elementos ou texto repetidos.

Abaixo está uma implementação de recursão que verifica ou faz um loop em cada elemento de todos os elementos DOM apenas uma vez e acrescenta:

(Créditos a @George Reith por sua resposta de recursão aqui: Mapear HTML para 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);

}
Yi Xiang Chong
fonte
-1

Você pode tentar com document.getElementsByClassName('special_class');

Jimish Gamit
fonte
4
O método correto é getElementsByClassName()e não é suportado pelo Internet Explorer até a versão 9.
Andy E