Javascript: จะวนซ้ำองค์ประกอบ DOM ทั้งหมดบนหน้าได้อย่างไร


156

ฉันพยายามที่จะวนรอบองค์ประกอบทั้งหมดในหน้าดังนั้นฉันต้องการตรวจสอบทุกองค์ประกอบที่มีอยู่ในหน้านี้เพื่อเรียนพิเศษ

ดังนั้นฉันจะบอกว่าฉันต้องการตรวจสอบทุกองค์ประกอบได้อย่างไร


1
คุณแน่ใจหรือไม่ว่าต้องการวนซ้ำทุกองค์ประกอบด้วยตัวเอง? ทำไมไม่ใช้ jquery และ selectors เพื่อจับองค์ประกอบที่มีในคลาสนั้น
NG

document.getElementsByTagName ไม่มีเมธอดใช่ไหม
SuperJedi224

* TL; DR:สำหรับองค์ประกอบที่มองเห็นได้อย่างเดียวให้ใช้:document.body.getElementsByTagName('*')
Andrew

พูดซ้ำกับ: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' เท่านั้น
Florian Müller

2
@ Florian: เช่นเดียวกับที่คุณเข้าถึงองค์ประกอบอาร์เรย์ - all[i]จะให้องค์ประกอบปัจจุบันกับคุณ
Andy E

2
วิธีการเลือกองค์ประกอบในด้านวง?
เดลิเดส

2
@JesseAldridge: เพียงพลังแห่งนิสัย / การปฏิบัติที่ดี การหลีกเลี่ยงการค้นหาคุณสมบัติในการวนซ้ำทุกครั้งจะเป็นการเพิ่มประสิทธิภาพขนาดเล็ก แต่ก็ไม่ยากที่จะเขียนและดังนั้นฉันจึงทำตามธรรมชาติ
Andy E

2
@ Jonathan getElementsByClassName()ได้รับการสนับสนุนที่แย่กว่าเดิมquerySelectorAll()(ไม่รองรับ IE 8 ในอดีต) OP ระบุไว้อย่างชัดเจนว่าเขาต้องการวนรอบองค์ประกอบทั้งหมดในหน้าซึ่งฉันให้วิธีการแก้ปัญหาแก่เขาและเสนอทางเลือกอื่น ฉันไม่แน่ใจว่าปัญหาอยู่ที่ ;-)
Andy 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 นำมา;)
Florian Müller

2
คุณลักษณะที่ยอดเยี่ยมของเรื่องนี้คือ nodeiterator ก็เดินไปตามลำดับที่ปรากฏใน 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]);
        }
    }
}

ไม่เหมือนกับคำแนะนำอื่น ๆ โซลูชันนี้ไม่ต้องการให้คุณสร้างอาร์เรย์สำหรับโหนดทั้งหมดดังนั้นจึงมีความสว่างมากขึ้นในหน่วยความจำ ที่สำคัญกว่านั้นจะพบผลลัพธ์มากขึ้น ฉันไม่แน่ใจว่าผลลัพธ์เหล่านั้นคืออะไร แต่เมื่อทดสอบกับ chrome พบว่ามีโหนดมากกว่า 50% เมื่อเทียบกับdocument.getElementsByTagName("*");


19
เวลาที่ดีที่สุดในการใช้การเรียกซ้ำเป็นเวลาที่ดีที่สุดในการใช้การสอบถามซ้ำ
Adamlive

8
“มัน founds ประมาณ 50% โหนดมากขึ้นในการเปรียบเทียบกับdocument.getElementsByTagName("*");” - ยุบก็จะพบต่อมน้ำข้อความและโหนดความคิดเห็นเช่นเดียวกับโหนดองค์ประกอบ เนื่องจาก OP เพิ่งจะถามเกี่ยวกับองค์ประกอบมันไม่จำเป็นเลย
Paul D. Waite

1
มันอาจจะเบาในหน่วยความจำ ขึ้นอยู่กับว่าคุณทำอะไรในแต่ละระดับของการเรียกซ้ำคุณสามารถสร้างสแต็กการโทรที่ยิ่งใหญ่ได้ตามเวลาที่คุณไปถึงด้านล่าง A NodeListเป็นการอ้างอิงNodes ที่สร้างขึ้นแล้วใน DOM ของคุณดังนั้นจึงไม่หนักอย่างที่คุณคิด คนที่รู้มากกว่าสามารถชั่งน้ำหนักได้ แต่ฉันคิดว่ามันเป็นเพียงขนาดอ้างอิงหน่วยความจำดังนั้น 8 ไบต์ต่อโหนด
Josh จาก Qaribou

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. ให้คำตอบที่ดี

ฉันจะเพิ่มถ้าคุณรู้สึกว่าเลือก childs ทั้งหมดในตัวเลือกพิเศษบางอย่าง (สิ่งนี้เกิดขึ้นกับฉันเมื่อเร็ว ๆ นี้) คุณสามารถใช้วิธี "getElementsByTagName ()" บนวัตถุ DOM ที่คุณต้องการ

ตัวอย่างเช่นฉันต้องการแยกส่วน "ภาพ" ของหน้าเว็บดังนั้นฉันจึงทำสิ่งนี้

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

นี้จะไม่คำนึงถึงส่วนหัว


ยอดเยี่ยม . . .
แอนดรู

2

จากลิงค์นี้
อ้างอิงจาวาสคริปต์

<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: แก้ไข

ตั้งแต่คำตอบสุดท้ายของฉันฉันพบโซลูชันที่ง่ายกว่าดีกว่า

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

    }

ตามการอภิปรายดังนั้นนี้ , เป็นกำลังใจในความโปรดปรานของdocument.all document.getElementBy*
thejoshwolfe

@thejoshwolfe ขอบคุณสิ่งที่คุณคิดว่าวิธีการแก้ปัญหา socond ของฉันฉันอัปเดต
shareef



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
Andy E
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.