Javascript: Wie werden ALLE DOM-Elemente auf einer Seite durchlaufen?

155

Ich versuche, ALLE Elemente auf einer Seite zu durchlaufen, daher möchte ich jedes auf dieser Seite vorhandene Element auf eine spezielle Klasse überprüfen.

Wie kann ich also sagen, dass ich JEDES Element überprüfen möchte?

Florian Müller
quelle
1
Sind Sie sicher, dass Sie jedes Element selbst durchlaufen möchten? Warum nicht jquery und Selektoren verwenden, um Elemente dieser bestimmten Klasse zu erfassen?
NG.
Gibt es keine document.getElementsByTagName-Methode?
SuperJedi224
* TL; DR: Verwenden Sie für nur sichtbare Elemente:document.body.getElementsByTagName('*')
Andrew
Iterieren mit:for (... of ...) { }
Andrew

Antworten:

252

Sie können ein *an übergeben getElementsByTagName(), damit alle Elemente auf einer Seite zurückgegeben werden:

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

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

Beachten Sie, dass Sie querySelectorAll(), falls verfügbar (IE9 +, CSS in IE8), nur Elemente mit einer bestimmten Klasse suchen können.

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

Dies würde sicherlich die Sache für moderne Browser beschleunigen.


Browser unterstützen jetzt foreach auf NodeList . Dies bedeutet, dass Sie die Elemente direkt schleifen können, anstatt Ihre eigene for-Schleife zu schreiben.

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

Leistungshinweis - Geben Sie Ihr Bestes, um das zu erfassen, wonach Sie suchen. Ein universeller Selektor kann abhängig von der Komplexität der Seite viele Knoten zurückgeben. Selbst wenn Sie alles durchsehen müssen, was jemand sehen kann, bedeutet dies, dass Sie 'body *'als Selektor den gesamten headInhalt ausschneiden können .

Andy E.
quelle
2
Diese Methode scheint sehr schön zu sein, aber wie kann ich ein Element in der oberen Methode auswählen? Ich habe nur den Index 'i'?
Florian Müller
2
@Florian: Genau wie Sie auf ein Array-Element zugreifen all[i]würden - würde Ihnen das aktuelle Element geben.
Andy E
2
Wie wähle ich das Element neben der Schleife aus?
Debiprasad
2
@ JesseAldridge: nur eine Kraft der Gewohnheit / gute Praxis. Das Vermeiden der Eigenschaftssuche bei jeder Iteration ist normalerweise eine Mikrooptimierung, aber es ist nicht besonders schwierig zu schreiben, und deshalb mache ich es einfach auf natürliche Weise.
Andy E
2
@ Jonathan getElementsByClassName()hat schlechtere Unterstützung als querySelectorAll()(ersteres wird in IE 8 nicht unterstützt). Das OP erklärte klar, dass er alle Elemente auf einer Seite durchlaufen möchte , für die ich ihm die Lösung gegeben und eine Alternative angeboten habe. Ich bin mir nicht sicher, wo das Problem liegt ;-).
Andy E
38

War auf der Suche nach dem gleichen. Nun, nicht genau. Ich wollte nur alle DOM-Knoten auflisten.

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

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

Um Elemente mit einer bestimmten Klasse zu erhalten, können wir die Filterfunktion verwenden.

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

Gefundene Lösung auf MDN

traditionell
quelle
Ich habe document.ceeateNodeIterator nie gesehen. Scheint interessant, welche neuen Funktionen JS bringt;)
Florian Müller
2
Ein cooles Feature dabei ist, dass der Nodeiterator die Knoten auch in der Reihenfolge durchläuft, in der sie im HTML angezeigt werden. Ich frage mich, ob einige von document.body.getElementsByTagName('*')ihnen die Knoten in verschlüsselter Reihenfolge zurückgeben könnten.
Zivilist
Wow, es wird tatsächlich gut unterstützt!
Rogerdpack
15

Wie immer ist die beste Lösung die Verwendung der Rekursion:

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

Im Gegensatz zu anderen Vorschlägen müssen Sie bei dieser Lösung nicht für alle Knoten ein Array erstellen, um den Speicher besser zu beleuchten. Noch wichtiger ist, dass mehr Ergebnisse erzielt werden. Ich bin mir nicht sicher, was diese Ergebnisse sind, aber beim Testen auf Chrom werden etwa 50% mehr Knoten im Vergleich zu gefundendocument.getElementsByTagName("*");

Ilya Gazman
quelle
19
Die beste Zeit für die Verwendung der Rekursion ist die beste Zeit für die Verwendung der Rekursion.
Adamlive
8
"Es werden ungefähr 50% mehr Knoten gefunden als document.getElementsByTagName("*");" - ja, es werden Textknoten und Kommentarknoten sowie Elementknoten gefunden . Da das OP nur nach Elementen fragte, ist das unnötig.
Paul D. Waite
1
Es könnte leichter im Speicher sein. Abhängig davon, wie viel Sie in jeder Rekursionsstufe tun, können Sie einen mächtig großen Aufrufstapel erstellen, bis Sie ganz unten sind. A NodeListverweist einfach auf die Nodes, die bereits in Ihrem DOM erstellt wurden. Es ist also nicht so schwer, wie Sie sich vorstellen können. Jemand, der mehr weiß, kann wiegen, aber ich denke, es ist nur eine Speicherreferenzgröße, also 8 Bytes pro Knoten.
Josh von Qaribou
9

Hier ist ein weiteres Beispiel, wie Sie ein Dokument oder ein Element durchlaufen können:

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

Für diejenigen, die Jquery verwenden

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

Andy E. gab eine gute Antwort.

Ich würde hinzufügen, wenn Sie alle Kinder in einem speziellen Selektor auswählen möchten (dies ist mir kürzlich passiert), können Sie die Methode "getElementsByTagName ()" auf jedes gewünschte DOM-Objekt anwenden.

Zum Beispiel musste ich nur den "visuellen" Teil der Webseite analysieren, also habe ich das einfach gemacht

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

Dies wird niemals den Kopfteil berücksichtigen.

Korvus
quelle
Ausgezeichnet! . . .
Andrew
2

von diesem Link
Javascript Referenz

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

seit meiner letzten antwort habe ich eine bessere einfachere lösung gefunden

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
quelle
nach dieser SO Diskussion , document.allwird zugunsten entmutigt document.getElementBy*.
Thejoshwolfe
@thejoshwolfe danke, was denkst du über meine zweite Lösung, die ich aktualisiert habe
shareef
0

Verwenden *

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

Ich denke, das ist wirklich schnell

document.querySelectorAll('body,body *').forEach(function(e) {
verteidige Orca
quelle
0

Es ist in Ordnung, alle Elemente zu verwenden, var all = document.getElementsByTagName("*"); for (var i=0, max=all.length; i < max; i++);wenn Sie jedes Element überprüfen müssen, dies jedoch dazu führt, dass sich wiederholende Elemente oder Texte überprüft oder wiederholt werden.

Im Folgenden finden Sie eine Rekursionsimplementierung, die jedes Element aller DOM-Elemente nur einmal überprüft oder schleift und anfügt:

(Dank an @George Reith für seine Rekursionsantwort hier: HTML zu JSON zuordnen )

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

Sie können mit versuchen document.getElementsByClassName('special_class');

Jimish Gamit
quelle
4
Die richtige Methode ist getElementsByClassName()und wird von Internet Explorer bis Version 9 nicht unterstützt.
Andy E