Javascript:如何遍历页面上的所有DOM元素?


155

我试图遍历页面上的所有元素,所以我想检查此页面上存在的每个元素是否有特殊类。

因此,怎么说我要检查每个元素?


1
您确定要自己遍历每个元素吗?为什么不使用jquery和选择器来获取该特定类的元素?
NG。

没有document.getElementsByTagName方法吗?
SuperJedi224

* TL; DR:对于仅可见元素,请使用:document.body.getElementsByTagName('*')
Andrew

迭代:for (... of ...) { }
安德鲁

Answers:


252

您可以将传递给*getElementsByTagName()以便它将返回页面中的所有元素:

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

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

请注意,您可以使用querySelectorAll()(如果可用)(IE9 +,IE8中的CSS)来查找具有特定类的元素。

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

对于现代浏览器而言,这无疑会加速事情的发展。


浏览器现在在NodeList上支持foreach。这意味着您可以直接循环元素,而不必编写自己的for循环。

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

性能说明 -尽最大努力确定您要寻找的内容。通用选择器可以根据页面的复杂性返回很多节点。即使您确实需要浏览别人可能看到的'body *'所有head内容,这也意味着您可以用作选择器来剪切所有内容。


2
该方法看起来非常好,但是如何在上层方法中选择一个元素?我只有索引“ i”吗?
FlorianMüller,2010年

2
@Florian:就像您访问数组元素一样- all[i]将为您提供当前元素。
安迪E

2
如何选择循环中的元素?
Debiprasad

2
@JesseAldridge:只是习惯/良好实践的力量。避免在每次迭代中进行属性查找通常是一个微优化,但是编写起来并不是特别困难,因此我自然而然地做到了。
安迪E

2
@Jonathan的getElementsByClassName()支持比querySelectorAll()(IE 8中不支持前者)要差。OP明确表示,他想遍历页面上的所有元素,为此我给了他解决方案并提供了替代方案。我不确定那是什么问题;-)。
安迪E

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带来了什么新功能似乎很有趣;)
FlorianMüller2014年

2
这样做的一个很酷的功能是,nodeiterator还会按照它们在html中出现的顺序遍历节点。我想知道其中一些是否document.body.getElementsByTagName('*')可以按加扰顺序返回节点。
文职人员2016年

哇,实际上得到了很好的支持!
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]);
        }
    }
}

与其他建议不同,此解决方案不需要您为所有节点创建一个数组,因此它在内存上的作用更大。更重要的是,它可以找到更多结果。我不确定这些结果如何,但是在chrome上进行测试时,发现与document.getElementsByTagName("*");


19
使用递归的最佳时间是使用递归的最佳时间。
亚当利夫(Adamlive)

8
“与之相比document.getElementsByTagName("*");,它发现的节点多出50%”-是的,它将找到文本节点,注释节点以及元素节点。由于OP只是在询问元素,所以没有必要。
Paul D. Waite,

1
可能是内存更轻。根据您在每个递归级别上执行的操作,您可以在到达最底层时建立一个巨大的调用堆栈。A NodeList只是引用Node您的DOM中已经内置的,因此它没有您想像的那么重。知道更多的人可以权衡一下,但是我认为这只是一个内存引用大小,因此每个节点8个字节。
来自Qaribou,2018年

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

安迪(Andy E.)给出了很好的答案。

我要补充一点,如果您想在某个特殊的选择器中选择所有子项(这种需求最近发生在我身上),则可以在所需的任何DOM对象上应用方法“ getElementsByTagName()”。

例如,我只需要解析网页的“可视”部分,因此我做了

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

@thejoshwolfe,谢谢您对我更新的第二个解决方案
有何看法

0

*

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

0

我认为这真的很快

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

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的支持
安迪·ê
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.