Javascript: Comment parcourir TOUS les éléments DOM sur une page?


156

J'essaie de faire une boucle sur TOUS les éléments d'une page, je veux donc vérifier chaque élément qui existe sur cette page pour une classe spéciale.

Alors, comment dire que je veux vérifier CHAQUE élément?


1
êtes-vous sûr de vouloir parcourir chaque élément vous-même? pourquoi ne pas utiliser jquery et des sélecteurs pour récupérer des éléments de cette classe particulière?
NG.

N'existe-t-il pas une méthode document.getElementsByTagName?
SuperJedi224

* TL; DR: Pour les éléments visibles uniquement, utilisez:document.body.getElementsByTagName('*')
Andrew le

Itérer avec:for (... of ...) { }
Andrew le

Réponses:


252

Vous pouvez passer un *à getElementsByTagName()pour qu'il renvoie tous les éléments d'une page:

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

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

Notez que vous pouvez utiliser querySelectorAll(), s'il est disponible (IE9 +, CSS dans IE8), pour trouver simplement des éléments avec une classe particulière.

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

Cela accélérerait certainement les choses pour les navigateurs modernes.


Les navigateurs prennent désormais en charge foreach sur NodeList . Cela signifie que vous pouvez directement boucler les éléments au lieu d'écrire votre propre boucle for.

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

Note de performance - Faites de votre mieux pour définir ce que vous recherchez. Un sélecteur universel peut renvoyer beaucoup de nœuds en fonction de la complexité de la page. Même si vous avez besoin de regarder à travers tout ce que quelqu'un peut voir, cela signifie que vous pouvez utiliser 'body *'comme sélecteur pour supprimer tout le headcontenu.


2
Cette méthode semble très agréable, mais comment puis-je sélectionner un élément dans la méthode supérieure? Je n'ai que l'index «i»?
Florian Müller

2
@Florian: tout comme vous accéderiez à un élément de tableau - all[i]vous donnerait l'élément actuel.
Andy E

2
Comment sélectionner l'élément à côté de la boucle?
Debiprasad

2
@JesseAldridge: juste une force d'habitude / bonne pratique. Éviter la recherche de propriété à chaque itération est généralement une micro-optimisation, mais ce n'est pas particulièrement plus difficile à écrire et je le fais donc naturellement.
Andy E

2
@Jonathan getElementsByClassName()a un support pire que querySelectorAll()(le premier n'est pas pris en charge dans IE 8). L'OP a clairement indiqué qu'il souhaitait boucler tous les éléments d'une page, pour laquelle je lui ai donné la solution et proposé une alternative. Je ne sais pas quel est le problème avec ça ;-).
Andy E

39

Je cherchais la même chose. Eh bien, pas exactement. Je voulais seulement lister tous les nœuds DOM.

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

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

Pour obtenir des éléments avec une classe spécifique, nous pouvons utiliser la fonction de filtre.

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

Solution trouvée sur MDN


jamais vu document.ceeateNodeIterator. Les nouvelles fonctionnalités apportées par JS semblent intéressantes;)
Florian Müller

2
Une caractéristique intéressante de ceci est que le nodeiterator parcourt également les nœuds dans l'ordre dans lequel ils apparaissent dans le html. Je me demande si certains d'entre eux document.body.getElementsByTagName('*')pourraient renvoyer les nœuds dans un ordre brouillé.
Civil

Wow c'est en fait bien supporté!
rogerdpack

15

Comme toujours, la meilleure solution est d'utiliser la récursivité:

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

Contrairement à d'autres suggestions, cette solution ne vous oblige pas à créer un tableau pour tous les nœuds, donc c'est plus léger sur la mémoire. Plus important encore, il trouve plus de résultats. Je ne sais pas quels sont ces résultats, mais lors des tests sur chrome, il trouve environ 50% de nœuds en plus par rapport àdocument.getElementsByTagName("*");


19
Le meilleur moment pour utiliser la récursivité est le meilleur moment pour utiliser la récursivité.
Adamlive

8
«Il trouve environ 50% de nœuds en plus par rapport à document.getElementsByTagName("*");» - oui, il trouvera des nœuds de texte et des nœuds de commentaire ainsi que des nœuds d'élément . Comme le PO ne posait que des questions sur les éléments, ce n'est pas nécessaire.
Paul D.Waite

1
Cela pourrait être plus léger sur la mémoire. En fonction de ce que vous faites à chaque niveau de récursivité, vous pouvez créer une pile d'appels extrêmement volumineuse au moment où vous atteignez le bas. A NodeListfait simplement référence aux Nodes qui sont déjà construits dans votre DOM, donc ce n'est pas aussi lourd que vous pourriez l'imaginer. Quelqu'un qui en sait plus peut peser, mais je pense que c'est juste une taille de référence de mémoire, donc 8 octets par nœud.
Josh de Qaribou le

9

Voici un autre exemple sur la façon dont vous pouvez parcourir un document ou un élément:

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


3

Andy E. a donné une bonne réponse.

J'ajouterais que si vous avez envie de sélectionner tous les enfants dans un sélecteur spécial (ce besoin m'est arrivé récemment), vous pouvez appliquer la méthode "getElementsByTagName ()" sur n'importe quel objet DOM de votre choix.

Pour un exemple, je devais simplement analyser la partie "visuelle" de la page Web, donc je viens de faire ceci

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

Cela ne prendra jamais en considération la partie tête.


Excellent! . . .
Andrew le

2

à partir de ce lien
référence 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>

MISE À JOUR: MODIFIER

depuis ma dernière réponse, j'ai trouvé une meilleure solution plus 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

    }

selon cette discussion SO , document.allest découragée en faveur de document.getElementBy*.
thejoshwolfe

@thejoshwolfe merci que pensez-vous de ma solution socond que j'ai mise à jour
shareef

0

Utilisation *

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

0

je pense que c'est vraiment rapide

document.querySelectorAll('body,body *').forEach(function(e) {

0

Obtenir tous les éléments en utilisant var all = document.getElementsByTagName("*"); for (var i=0, max=all.length; i < max; i++); est acceptable si vous devez vérifier chaque élément, mais cela entraînera la vérification ou la mise en boucle d'éléments ou de texte répétitifs.

Voici une implémentation de récursivité qui vérifie ou boucle chaque élément de tous les éléments DOM une seule fois et ajoute:

(Crédits à @George Reith pour sa réponse sur la récursivité ici: Mapper HTML en 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

Vous pouvez essayer avec document.getElementsByClassName('special_class');


4
La méthode correcte est getElementsByClassName()et n'est pas prise en charge par Internet Explorer jusqu'à la version 9.
Andy E
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.