Javascript: ¿Cómo recorrer TODOS los elementos DOM en una página?

156

Estoy tratando de recorrer TODOS los elementos en una página, así que quiero verificar cada elemento que existe en esta página para una clase especial.

Entonces, ¿cómo digo que quiero verificar CADA elemento?

Florian Müller
fuente
1
¿estás seguro de que quieres recorrer cada elemento tú mismo? ¿por qué no usar jquery y selectores para capturar elementos que son de esa clase en particular?
NG.
¿No hay un método document.getElementsByTagName?
SuperJedi224
* TL; DR: Para elementos solo visibles, use:document.body.getElementsByTagName('*')
Andrew
Iterar con:for (... of ...) { }
Andrew

Respuestas:

252

Puede pasar un *a getElementsByTagName()para que devuelva todos los elementos de una página:

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

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

Tenga en cuenta que podría usar querySelectorAll(), si está disponible (IE9 +, CSS en IE8), solo para encontrar elementos con una clase en particular.

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

Esto sin duda aceleraría las cosas para los navegadores modernos.


Los navegadores ahora admiten foreach en NodeList . Esto significa que puede hacer un bucle directo de los elementos en lugar de escribir su propio bucle for.

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

Nota de rendimiento : haga todo lo posible para determinar lo que está buscando. Un selector universal puede devolver muchos nodos dependiendo de la complejidad de la página. Incluso si necesita revisar todo lo que alguien puede ver, eso significa que puede usarlo 'body *'como selector para cortar todo el headcontenido.

Andy E
fuente
2
Este método parece muy bueno, pero ¿cómo puedo seleccionar un elemento en el método superior? ¿Solo obtuve el índice 'i'?
Florian Müller el
2
@Florian: al igual que accedería a un elemento de matriz, all[i]le daría el elemento actual.
Andy E
2
¿Cómo seleccionar el elemento en el lado del bucle?
Debiprasad
2
@JesseAldridge: solo una fuerza de hábito / buena práctica. Evitar la búsqueda de propiedades en cada iteración suele ser una microoptimización, pero no es particularmente más difícil de escribir, por lo que lo hago de forma natural.
Andy E
2
@ Jonathan getElementsByClassName()tiene peor soporte que querySelectorAll()(el primero no es compatible con IE 8). El OP declaró claramente que desea recorrer todos los elementos de una página, para lo cual le di la solución y le ofrecí una alternativa. No estoy seguro de cuál es el problema con eso ;-).
Andy E
39

Estaba buscando lo mismo. Bueno no exactamente. Solo quería enumerar todos los nodos DOM.

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

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

Para obtener elementos con una clase específica, podemos usar la función 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);
}

Solución encontrada en MDN

tradicional
fuente
nunca vi document.ceeateNodeIterator. Parece interesante qué nuevas características trae JS;)
Florian Müller
2
Una característica interesante de esto es que el nodeiterator también recorre los nodos en el orden en que aparecen en el html. Me pregunto si algunos document.body.getElementsByTagName('*')podrían devolver los nodos en orden revuelto.
Civil
¡Guau, en realidad está bien soportado!
rogerdpack
15

Como siempre, la mejor solución es usar la recursividad:

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

A diferencia de otras sugerencias, esta solución no requiere que cree una matriz para todos los nodos, por lo que es más ligera en la memoria. Más importante aún, encuentra más resultados. No estoy seguro de cuáles son esos resultados, pero cuando prueba en Chrome, encuentra aproximadamente un 50% más de nodos en comparación condocument.getElementsByTagName("*");

Ilya Gazman
fuente
19
El mejor momento para usar la recursión es el mejor momento para usar la recursividad.
Adamlive
8
"Encuentra aproximadamente un 50% más de nodos en comparación con document.getElementsByTagName("*");" - sí, encontrará nodos de texto y nodos de comentarios, así como nodos de elementos . Como el OP solo preguntaba sobre elementos, eso es innecesario.
Paul D. Waite
1
Se podría ser más claro en la memoria. Dependiendo de cuánto hagas en cada nivel de recursión, puedes construir una pila de llamadas poderosamente grande para cuando llegues al fondo. A NodeListsimplemente hace referencia a los Nodes que ya están construidos en su DOM, por lo que no es tan pesado como podría imaginar. Alguien que sabe más puede influir, pero creo que es solo un tamaño de referencia de memoria, por lo que 8 bytes por nodo.
Josh de Qaribou
9

Aquí hay otro ejemplo sobre cómo puede recorrer un documento o un 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
fuente
4

Para aquellos que usan Jquery

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

Andy E. dio una buena respuesta.

Agregaría que si desea seleccionar todos los elementos secundarios en un selector especial (esto me sucedió recientemente), puede aplicar el método "getElementsByTagName ()" en cualquier objeto DOM que desee.

Por ejemplo, solo necesitaba analizar parte "visual" de la página web, así que hice esto

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

Esto nunca tendrá en cuenta la parte de la cabeza.

korvus
fuente
¡Excelente! . . .
Andrew
2

desde este enlace
referencia de javascript

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

ACTUALIZACIÓN: EDITAR

desde mi última respuesta encontré una solución mejor y más simple

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
fuente
de acuerdo con esta discusión SO , document.allse desaconseja a favor de document.getElementBy*.
thejoshwolfe
@thejoshwolfe gracias ¿Qué opinas de mi solución Socond He actualizado
shareef
0

Utilizar *

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

creo que esto es muy rápido

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

Hacer que todos los elementos se utilicen var all = document.getElementsByTagName("*"); for (var i=0, max=all.length; i < max; i++);está bien si necesita verificar cada elemento pero resultará en verificar o repetir elementos o texto repetidos.

A continuación se muestra una implementación de recursión que comprueba o repite cada elemento de todos los elementos DOM solo una vez y agrega:

(Créditos a @George Reith por su respuesta recurrente aquí: Mapa HTML a 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
fuente
-1

Puedes probar con document.getElementsByClassName('special_class');

Jimish Gamit
fuente
44
El método correcto es getElementsByClassName()y no es compatible con Internet Explorer hasta la versión 9.
Andy E