Javascript: Як переглядати ВСІ елементи DOM на сторінці?


155

Я намагаюся перетворити цикл на ВСІ елементи на сторінці, тому хочу перевірити кожен елемент, який існує на цій сторінці, на наявність спеціального класу.

Отже, як я можу сказати, що хочу перевірити КОЖНИЙ елемент?


1
ви впевнені, що хочете пройти цикл кожного елемента самостійно? чому б не використовувати jquery та селектори, щоб захопити елементи, що належать до цього класу?
НГ.

Чи не існує методу document.getElementsByTagName?
SuperJedi224

* TL; DR: Для елементів, які бачать лише видимість, використовуйте:document.body.getElementsByTagName('*')
Андрій

Повторити з:for (... of ...) { }
Андрій

Відповіді:


252

Ви можете передати "а", *щоб getElementsByTagName()він повернув усі елементи сторінки:

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

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

Зауважте, що ви можете використовувати querySelectorAll(), якщо це доступно (IE9 +, CSS в IE8), просто знайти елементи з певним класом.

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

Це, безумовно, пришвидшило б питання сучасних браузерів.


Зараз браузери підтримують foreach на NodeList . Це означає, що ви можете безпосередньо циклічити елементи замість того, щоб писати власні для циклу.

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

Примітка про ефективність - Майте все можливе, щоб розширити те, що ви шукаєте. Універсальний селектор може повернути безліч вузлів залежно від складності сторінки. Навіть якщо вам потрібно переглянути все, що хтось може бачити, це означає, що ви можете використовувати 'body *'як селектор, щоб вирізати весь headвміст.


2
Цей метод здається дуже приємним, але як я можу вибрати елемент у верхньому методі? Я отримав лише індекс 'i'?
Флоріан Мюллер

2
@Florian: так само, як ви отримаєте доступ до елемента масиву - all[i]дав би вам поточний елемент.
Енді Е

2
Як вибрати елемент в бічній петлі?
Debiprasad

2
@JesseAldridge: просто сила звички / хороша практика. Уникання пошуку властивостей на кожній ітерації, як правило, є мікрооптимізацією, але писати це не особливо складно, і тому я це роблю природно.
Енді Е

2
@Jonathan getElementsByClassName()має гіршу підтримку, ніж querySelectorAll()(перший не підтримується в IE 8). ОП чітко заявила, що він хоче переключити всі елементи на сторінці, для чого я дав йому рішення і запропонував альтернативу. Я не впевнений, у чому проблема з цим ;-).
Енді Е

39

Шукав те саме. Ну не зовсім. Я хотів лише перерахувати всі DOM-вузли.

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

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

Щоб отримати елементи з певним класом, ми можемо використовувати функцію фільтра.

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

Знайдено рішення на MDN


ніколи не бачив document.ceeateNodeIterator. Цікаво здається, які нові функції приносить JS;)
Флоріан Мюллер

2
Прикольною особливістю цього є те, що вузлик також ходить по вузлах у порядку, який вони відображаються в html. Цікаво, чи хтось із них document.body.getElementsByTagName('*')міг би повернути вузли в зашифрованому порядку.
Цивільний

Ого, це насправді добре підтримується!
rogerdpack

15

Як завжди, найкращим рішенням є використання рекурсії:

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

На відміну від інших пропозицій, для цього рішення не потрібно створювати масив для всіх вузлів, тому його більше світла в пам'яті. Що ще важливіше, він знаходить більше результатів. Я не впевнений, що це за результати, але при тестуванні на хром виявляється приблизно на 50% більше вузлів порівняно зdocument.getElementsByTagName("*");


19
Найкращий час для використання рекурсії - найкращий час для використання рекурсії.
Адамлів

8
"Він знайде приблизно на 50% більше вузлів порівняно з document.getElementsByTagName("*");" - так, там ви знайдете текстові вузли та вузли коментарів, а також вузли елементів . Оскільки ОП просто розпитувала про елементи, це непотрібно.
Пол Д. Уейт

1
Це може бути легше на пам’яті. Залежно від того, скільки ви робите в кожному рівні рекурсії, ви можете створити величезний стек викликів до моменту, коли ви досягнете нижнього рівня. A NodeList- це просто посилання на NodeS, які вже побудовані у вашому DOM, тому це не так важко, як ви могли собі уявити. Хтось, хто знає більше, може зважити вагу, але я думаю, що це лише розмір опорної пам’яті, тому 8 байт на вузол.
Джош з Карібу

9

Ось ще один приклад того, як ви можете провести цикл через документ або елемент:

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

Енді Е. дав хорошу відповідь.

Я додам, якщо ви хочете виділити всіх дітей у якомусь спеціальному селекторі (ця потреба трапилася зі мною недавно), ви можете застосувати метод "getElementsByTagName ()" до будь-якого об'єкта DOM, який ви хочете.

Для прикладу, мені потрібно було просто проаналізувати "візуальну" частину веб-сторінки, тому я просто зробив це

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

Це ніколи не братиме до уваги головну частину.


Відмінно! . . .
Андрій

2

з цього посилання
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>

ОНОВЛЕННЯ: редагувати

з моєї останньої відповіді я знайшов краще простіше рішення

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

    }

згідно з цією дискусією SO , document.allне рекомендується на користь document.getElementBy*.
thejoshwolfe

@thejoshwolfe дякую, що ти думаєш про моє рішення, яке я оновив
shareef

0

Використовуйте *

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


0

var all = document.getElementsByTagName("*"); for (var i=0, max=all.length; i < max; i++);Добре використовувати всі елементи , якщо вам потрібно перевірити кожен елемент, але це призведе до перевірки або циклічного повторення елементів або тексту.

Нижче представлена ​​рекурсійна реалізація, яка перевіряє або циклічно обробляє кожен елемент усіх елементів DOM лише один раз та додає:

(Подяки @George Reith за його рекурсійну відповідь тут: Позначте HTML на 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

Можна спробувати document.getElementsByClassName('special_class');


4
Правильний метод є getElementsByClassName()і він не підтримується Internet Explorer до версії 9.
Енді Е
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.