JavaScript: jak przeglądać WSZYSTKIE elementy DOM na stronie?

155

Próbuję zapętlić WSZYSTKIE elementy na stronie, więc chcę sprawdzić każdy element, który istnieje na tej stronie, pod kątem specjalnej klasy.

Jak więc mam powiedzieć, że chcę sprawdzić KAŻDY element?

Florian Müller
źródło
1
czy na pewno chcesz samodzielnie przejrzeć każdy element? dlaczego nie użyć jquery i selektorów do pobrania elementów należących do tej konkretnej klasy?
NG.
Czy nie ma metody document.getElementsByTagName?
SuperJedi224
* TL; DR: W przypadku elementów tylko widocznych użyj:document.body.getElementsByTagName('*')
Andrew
Iteruj z:for (... of ...) { }
Andrew

Odpowiedzi:

252

Możesz przekazać *do, getElementsByTagName()aby zwróciło wszystkie elementy na stronie:

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

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

Zauważ, że możesz użyć querySelectorAll(), jeśli jest dostępny (IE9 +, CSS w IE8), aby po prostu znaleźć elementy z określoną klasą.

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

To z pewnością przyspieszyłoby sprawy nowoczesnych przeglądarek.


Przeglądarki obsługują teraz foreach w NodeList . Oznacza to, że możesz bezpośrednio zapętlić elementy zamiast pisać własną pętlę for.

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

Uwaga dotycząca wydajności - postaraj się określić zakres tego, czego szukasz. Uniwersalny selektor może zwrócić wiele węzłów w zależności od złożoności strony. Nawet jeśli musisz przejrzeć wszystko, co ktoś może zobaczyć, oznacza to, że możesz użyć 'body *'selektora, aby wyciąć całą headzawartość.

Andy E.
źródło
2
Ta metoda wydaje się bardzo fajna, ale jak mogę wybrać element w górnej metodzie? Mam tylko indeks „i”?
Florian Müller
2
@Florian: tak jak w przypadku dostępu do elementu tablicy - all[i]daje ci bieżący element.
Andy E
2
Jak wybrać element w bocznej pętli?
Debiprasad
2
@JesseAldridge: po prostu siła przyzwyczajenia / dobrych praktyk. Unikanie wyszukiwania właściwości w każdej iteracji jest zwykle mikro-optymalizacją, ale nie jest szczególnie trudne do napisania, więc po prostu robię to naturalnie.
Andy E
2
@Jonathan getElementsByClassName()ma gorsze wsparcie niż querySelectorAll()(to pierwsze nie jest obsługiwane w IE 8). OP wyraźnie stwierdził, że chce zapętlić wszystkie elementy na stronie, dla czego dałem mu rozwiązanie i zaproponowałem alternatywę. Nie jestem pewien, w czym problem ;-).
Andy E
39

Szukałem tego samego. Cóż, nie do końca. Chciałem tylko wymienić wszystkie węzły DOM.

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

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

Aby uzyskać elementy o określonej klasie, możemy użyć funkcji filtru.

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

Znalazłem rozwiązanie na MDN

tradycyjny
źródło
nigdy nie widziałem document.ceeateNodeIterator. Ciekawe, jakie nowe funkcje wprowadza JS;)
Florian Müller
2
Fajną cechą tego jest to, że nodeiterator również porusza się po węzłach w kolejności, w jakiej pojawiają się w html. Zastanawiam się, czy niektóre z nich document.body.getElementsByTagName('*')mogłyby zwrócić węzły w zakodowanej kolejności.
Cywil
Wow, to naprawdę dobrze obsługiwane!
rogerdpack
15

Jak zawsze najlepszym rozwiązaniem jest użycie rekurencji:

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

W przeciwieństwie do innych sugestii, to rozwiązanie nie wymaga tworzenia tablicy dla wszystkich węzłów, więc ma więcej światła na pamięć. Co ważniejsze, znajduje więcej wyników. Nie jestem pewien, jakie to są wyniki, ale podczas testów na Chrome znajduje około 50% więcej węzłów w porównaniu zdocument.getElementsByTagName("*");

Ilya Gazman
źródło
19
Najlepszy czas na użycie rekurencji to najlepszy czas na użycie rekurencji.
Adamlive
8
„Znajduje około 50% więcej węzłów w porównaniu z document.getElementsByTagName("*");” - tak, znajdzie węzły tekstowe i komentarze, a także węzły elementów . Ponieważ OP pytał tylko o elementy, to jest niepotrzebne.
Paul D. Waite
1
To może być lżejszy pamięci. W zależności od tego, ile robisz na każdym poziomie rekurencji, możesz zbudować potężnie duży stos wywołań, zanim dojdziesz do końca. A NodeListpo prostu odwołuje się do Nodes, które są już zbudowane w twoim DOM, więc nie jest tak ciężki, jak możesz sobie wyobrazić. Ktoś, kto wie więcej, może ważyć, ale myślę, że to tylko rozmiar odniesienia pamięci, więc 8 bajtów na węzeł.
Josh z Qaribou
9

Oto kolejny przykład, jak można zapętlić dokument lub element:

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
źródło
4

Dla tych, którzy używają Jquery

$("*").each(function(i,e){console.log(i+' '+e)});
Matas Vaitkevicius
źródło
3

Andy E. udzielił dobrej odpowiedzi.

Dodałbym, że jeśli chcesz zaznaczyć wszystkie dzieci w jakimś specjalnym selektorze (taka potrzeba mi się ostatnio zdarzyła), możesz zastosować metodę „getElementsByTagName ()” na dowolnym obiekcie DOM.

Na przykład musiałem po prostu przeanalizować „wizualną” część strony internetowej, więc właśnie to zrobiłem

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

To nigdy nie będzie uwzględniać części głowy.

korvus
źródło
Doskonały! . . .
Andrew
2

z tego linku
odniesienie 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>

AKTUALIZACJA: EDYCJA

od czasu mojej ostatniej odpowiedzi znalazłem lepsze i prostsze rozwiązanie

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
źródło
zgodnie z tą dyskusją SO , document.allodradza się document.getElementBy*.
thejoshwolfe
@thejoshwolfe dzięki, co myślisz o moim rozwiązaniu socond. Zaktualizowałem
shareef
0

Posługiwać się *

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

myślę, że to jest naprawdę szybkie

document.querySelectorAll('body,body *').forEach(function(e) {
bronić orki
źródło
0

Pobranie wszystkich elementów za pomocą var all = document.getElementsByTagName("*"); for (var i=0, max=all.length; i < max; i++);jest w porządku, jeśli chcesz sprawdzić każdy element, ale spowoduje sprawdzenie lub zapętlenie powtarzających się elementów lub tekstu.

Poniżej znajduje się implementacja rekurencyjna, która sprawdza lub zapętla każdy element wszystkich elementów DOM tylko raz i dołącza:

(Podziękowania dla @George Reith za jego rekursywną odpowiedź tutaj: Mapuj HTML na 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
źródło
-1

Możesz spróbować document.getElementsByClassName('special_class');

Jimish Gamit
źródło
4
Prawidłowa metoda jest getElementsByClassName()i nie jest obsługiwana przez Internet Explorer do wersji 9.
Andy E