จะรับองค์ประกอบลูกตามชื่อชั้นได้อย่างไร?


132

ฉันกำลังพยายามหาช่วงเด็กที่มี class = 4 นี่คือองค์ประกอบตัวอย่าง:

<div id="test">
 <span class="one"></span>
 <span class="two"></span>
 <span class="three"></span>
 <span class="four"></span>
</div>

เครื่องมือที่ฉันมีคือ JS และ YUI2 ฉันสามารถทำสิ่งนี้ได้:

doc = document.getElementById('test');
notes = doc.getElementsByClassName('four');

//or

doc = YAHOO.util.Dom.get('#test');
notes = doc.getElementsByClassName('four');

สิ่งเหล่านี้ใช้ไม่ได้ใน IE ฉันได้รับข้อผิดพลาดว่าวัตถุ (doc) ไม่รองรับเมธอดหรือคุณสมบัตินี้ (getElementsByClassName) ฉันได้ลองใช้ตัวอย่างบางส่วนของการใช้งาน getElementsByClassName แบบข้ามเบราว์เซอร์แล้ว แต่ไม่สามารถใช้งานได้และยังคงได้รับข้อผิดพลาดนั้น

ฉันคิดว่าสิ่งที่ฉันต้องการคือ getElementsByClassName ข้ามเบราว์เซอร์หรือฉันต้องใช้ doc.getElementsByTagName ('span') และวนซ้ำจนกว่าฉันจะพบคลาส 4 ฉันไม่แน่ใจว่าจะทำอย่างไร


นี่
ไง

1
พอตลกก็ยิ่งมีประสิทธิภาพมากขึ้นquerySelectorAllได้รับการสนับสนุนโดย IE 8+ ในขณะที่getElementsByClassNameIE 9+ รองรับเท่านั้น หากคุณสามารถวาง IE 7 ได้แสดงว่าคุณใช้งานquerySelectorAll('.4')ได้อย่างปลอดภัย อย่างไรก็ตาม4เป็นชื่อคลาสที่ไม่ถูกต้อง
Prinzhorn

@paritybit คำถามนั้นใช้ไม่ได้เพราะยังคงใช้ getElementsByClassName และ IE เวอร์ชันเก่าดูเหมือนจะไม่รองรับ แก้ไข: ขออภัยที่ใช้ชื่อแท็ก วิธีนี้อาจใช้ได้ผล
spyderman4g63

@Prinzhorn ฉันไม่มียูทิลิตี้ตัวเลือก YUI2 ในผลิตภัณฑ์นี้ด้วยเหตุผลบางประการ
spyderman4g63

@ spyderman4g63 ฉันไม่ได้พูดถึงอะไรเฉพาะ YUI2 document.querySelectorAllเป็น DOM และไม่มีส่วนเกี่ยวข้องกับ YUI
Prinzhorn

คำตอบ:


85

ใช้doc.childNodesเพื่อวนซ้ำแต่ละรายการspanจากนั้นกรองรายการที่มีclassNameค่าเท่ากับ4:

var doc = document.getElementById("test");
var notes = null;
for (var i = 0; i < doc.childNodes.length; i++) {
    if (doc.childNodes[i].className == "4") {
      notes = doc.childNodes[i];
      break;
    }        
}


1
ปัญหาคือ getElementsByClassName ไม่ทำงานใน IE8
spyderman4g63

7
รหัสนี้ใช้ไม่ได้หากองค์ประกอบมีมากกว่าหนึ่งคลาส ตัวอย่างเช่นหากคุณกำลังมองหาองค์ประกอบที่มีคลาส "หนึ่ง" และองค์ประกอบของคุณมีคลาส "หนึ่งสองสาม" ฟังก์ชันนี้จะไม่พบ
Fran Verona

3
@FranVerona เพียงแค่อยากรู้อยากเห็นจะไม่ง่าย "indexOf ('className')> -1" แก้ปัญหาหลายชั้น?
James Poulose

2
@JamesPoulose ก็จะไม่ พิจารณากำหนดองค์ประกอบเป็นสองชั้นเรียน: เล็กและใหญ่ thatElement.className จะส่งคืนสตริงที่เท่ากับ "เล็กใหญ่กว่า" หากคุณกำลังมองหาคลาสที่เรียกว่า big โดยพูดว่า myElement.className.indexOf ("big") จะทำให้เกิดสิ่งที่ไม่เท่ากันกับค่าลบ 1 แม้ว่าจะไม่ได้เป็นส่วนหนึ่งของคลาสก็ตาม หากคุณสามารถควบคุมชื่อชั้นเรียนของคุณได้ 100% การแก้ไขดังกล่าวจะได้ผลก็ไม่รับประกันว่าจะทำได้โดยเฉพาะอย่างยิ่งเมื่อคุณเขียนโค้ดที่จะโต้ตอบกับโค้ดที่คุณไม่สามารถควบคุมได้ทั้งหมด
deadboy

คุณควรใช้การจับคู่ regex ในclassNameลักษณะนี้if(doc.childNode[i].className.match("\s*" + search_class + "\s*")โดยที่ตัวแปรsearch_classคือชื่อคลาสที่คุณกำลังมองหา
WebWanderer

131

ใช้ querySelector และ querySelectorAll

var testContainer = document.querySelector('#test');
var fourChildNode = testContainer.querySelector('.four');

IE9 ขึ้นไป

;)


ขอบคุณสำหรับโซลูชันที่ชาญฉลาดของคุณ!
ไทจินหยวน

1
สิ่งนี้จะตรวจสอบสำหรับผู้สืบเชื้อสายทั้งหมดไม่ใช่เฉพาะเด็ก
SUM1

47

คำตอบที่ยอมรับจะตรวจสอบเด็กในทันทีเท่านั้น บ่อยครั้งที่เรามองหาผู้สืบทอดที่มีชื่อคลาสนั้น

นอกจากนี้บางครั้งเราต้องการเด็กที่มี className

ตัวอย่างเช่น<div class="img square"></div>ควรจะตรงกับการค้นหาบน className "img" แม้ว่ามันเป็นที่แน่นอน className ไม่ได้ "img"

นี่เป็นวิธีแก้ปัญหาสำหรับปัญหาทั้งสองนี้:

ค้นหาอินสแตนซ์แรกขององค์ประกอบที่สืบทอดกับคลาส className

   function findFirstChildByClass(element, className) {
        var foundElement = null, found;
        function recurse(element, className, found) {
            for (var i = 0; i < element.childNodes.length && !found; i++) {
                var el = element.childNodes[i];
                var classes = el.className != undefined? el.className.split(" ") : [];
                for (var j = 0, jl = classes.length; j < jl; j++) {
                    if (classes[j] == className) {
                        found = true;
                        foundElement = element.childNodes[i];
                        break;
                    }
                }
                if(found)
                    break;
                recurse(element.childNodes[i], className, found);
            }
        }
        recurse(element, className, false);
        return foundElement;
    }

7
Nope ฉันไม่ต้องการลูกหลานทุกคนเพียง แต่เด็กเหมือนคำถามที่ถาม
Paul Draper

14
ลูกหมี ความคิดเห็นของคุณจำเป็น ดีใจที่ได้ช่วยอีก 13 คนที่ (เช่นฉัน) มักค้นหาคำตอบที่คล้ายกันเพื่อแก้ปัญหาที่คล้ายกัน แต่อาจซับซ้อนกว่าหรือทั่วไป
Augie Gardner

5
tnx ฉันคิดว่าคำตอบนี้เหมาะกับกรณีการใช้งานมากกว่า
Boban Stojanovski

สำหรับบันทึกฉันมีทั้งกรณีการใช้งานลูกหลานบ่อยกว่าเล็กน้อย แต่ฉันมาที่นี่เพื่อใช้กรณีเด็ก
SUM1

14

ใช้ element.querySelector () สมมติว่า: 'myElement' เป็นองค์ประกอบหลักที่คุณมีอยู่แล้ว 'sonClassName' คือคลาสของเด็กที่คุณกำลังมองหา

let child = myElement.querySelector('.sonClassName');

สำหรับข้อมูลเพิ่มเติมโปรดไปที่: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector


ด้วยเหตุผลบางอย่างฉันต้องใช้let child = myElement.querySelector('sonClassName');ในกรณีของฉัน
malat

แต่คุณต้องเพิ่มจุดถัดจาก class name querySelector (". sonClassName ') มิฉะนั้นจะจัดการเป็น sonClassName เป็นชื่อแท็กไม่ใช่ชื่อคลาส
Hamza Dahmoun

10

คุณสามารถลอง:

notes = doc.querySelectorAll('.4');

หรือ

notes = doc.getElementsByTagName('*');
for (var i = 0; i < notes.length; i++) { 
    if (notes[i].getAttribute('class') == '4') {
    }
}

1
ฉันสงสัยว่าในที่สุดเบราว์เซอร์ก็มีฟังก์ชันนี้โดยไม่ต้องใช้ jQuery หรือไม่ดีใจที่ได้เห็น หากใครอยากรู้อยากเห็นดูเหมือนว่ามันได้รับการสนับสนุนในเบราว์เซอร์ที่ทันสมัยที่สุด: developer.mozilla.org/en-US/docs/Web/API/Document/…
Liron Yahdav

8

สำหรับฉันดูเหมือนว่าคุณต้องการช่วงที่สี่ ในกรณีนี้คุณสามารถทำได้:

document.getElementById("test").childNodes[3]

หรือ

document.getElementById("test").getElementsByTagName("span")[3]

อันสุดท้ายนี้ช่วยให้มั่นใจได้ว่าไม่มีโหนดใด ๆ ที่ซ่อนอยู่ซึ่งอาจทำให้เกิดความสับสนได้


1
ขอบคุณ แต่องค์ประกอบย่อยมีหลายแบบ
spyderman4g63

1
สำหรับฉันแล้วดูเหมือนว่าคำถามคือการได้ลูกช่วงที่สี่เสมอจึงนำไปสู่คำตอบของฉัน แน่นอนฉันยอมรับว่าฟังก์ชันที่จะได้รับองค์ประกอบประเภทใดก็ตามที่ดัชนีใดก็ตามภายในองค์ประกอบอื่น ๆ จะดีกว่า แต่ฉันไม่ได้ตีความคำถามแบบนั้น ... อ่านคำถามอีกครั้งฉันเห็นว่าฉันเข้าใจผิดทั้งหมด: - )
Christian Jørgensen

TagNameแค่นั้นแหละ! ง่ายมาก
Jacksonkr

ฉันใช้เทคนิคนี้บ่อยๆเพื่อรับองค์ประกอบแรกเช่น document.getElementById ("test") childNodes [0]
Louise Eggleton

@LouiseEggleton มี .firstChildและ.firstChildElementแม้ว่า
YakovL

4

getElementsByClassNameแต่ทราบว่าเบราว์เซอร์เก่าไม่สนับสนุน

จากนั้นคุณสามารถทำได้

function getElementsByClassName(c,el){
    if(typeof el=='string'){el=document.getElementById(el);}
    if(!el){el=document;}
    if(el.getElementsByClassName){return el.getElementsByClassName(c);}
    var arr=[],
        allEls=el.getElementsByTagName('*');
    for(var i=0;i<allEls.length;i++){
        if(allEls[i].className.split(' ').indexOf(c)>-1){arr.push(allEls[i])}
    }
    return arr;
}
getElementsByClassName('4','test')[0];

ดูเหมือนว่าจะใช้งานได้ แต่โปรดทราบว่าคลาส HTML

  • ต้องขึ้นต้นด้วยตัวอักษร AZ หรือ az
  • สามารถตามด้วยตัวอักษร (A-Za-z) ตัวเลข (0-9) ขีดกลาง ("-") และขีดล่าง ("_")

3

ใช้ชื่อรหัสโดยgetElementByIdไม่มี#เครื่องหมายนำหน้า จากนั้นคุณจะได้รับspanโหนดลูกโดยใช้getElementsByTagNameและวนซ้ำเพื่อค้นหาโหนดที่มีคลาสที่เหมาะสม:

var doc = document.getElementById('test');

var c = doc.getElementsByTagName('span');

var e = null;
for (var i = 0; i < c.length; i++) {
    if (c[i].className == '4') {
        e = c[i];
        break;
    }
}

if (e != null) {
    alert(e.innerHTML);
}

การสาธิต: http://jsfiddle.net/Guffa/xB62U/


ขออภัย # เป็นการพิมพ์ผิด ฉันสามารถเลือกคอนเทนเนอร์ div แต่ไม่สามารถเลือกองค์ประกอบลูกด้วยชื่อแท็กได้เนื่องจากฟังก์ชันนั้นไม่ทำงานใน ie8
spyderman4g63

@ spyderman4g63: getElementsByTagNameวิธีการนี้ทำงานใน IE 8 ได้รับการสนับสนุนย้อนหลังไปถึง IE 5.5 developer.mozilla.org/en-US/docs/DOM/…
Guffa

3

ในความคิดของฉันทุกครั้งที่ทำได้คุณควรใช้ Array และวิธีการของมัน พวกมันเร็วกว่ามากจากนั้นวนซ้ำ DOM / wrapper ทั้งหมดหรือผลักสิ่งต่างๆลงในอาร์เรย์ว่าง โซลูชันส่วนใหญ่ที่นำเสนอที่นี่คุณสามารถเรียกว่าไร้เดียงสาตามที่อธิบายไว้ที่นี่ (บทความที่ยอดเยี่ยม btw):

https://medium.com/@chuckdries/traversing-the-dom-with-filter-map-and-arrow-functions-1417d326d2bc

วิธีแก้ปัญหาของฉัน : (ดูตัวอย่างสดบน Codepen: https://codepen.io/Nikolaus91/pen/wEGEYe )

const wrapper = document.getElementById('test') // take a wrapper by ID -> fastest
const itemsArray = Array.from(wrapper.children) // make Array from his children

const pickOne = itemsArray.map(item => { // loop over his children using .map() --> see MDN for more
   if(item.classList.contains('four')) // we place a test where we determine our choice
     item.classList.add('the-chosen-one') // your code here
})



1

นี่คือวิธีแก้ปัญหาแบบวนซ้ำที่ค่อนข้างง่าย ฉันคิดว่าการค้นหาแบบกว้างเป็นอันดับแรกเหมาะสมที่นี่ สิ่งนี้จะส่งคืนองค์ประกอบแรกที่ตรงกับคลาสที่พบ

function getDescendantWithClass(element, clName) {
    var children = element.childNodes;
    for (var i = 0; i < children.length; i++) {
        if (children[i].className &&
            children[i].className.split(' ').indexOf(clName) >= 0) {
            return children[i];
         }
     }
     for (var i = 0; i < children.length; i++) {
         var match = getDescendantWithClass(children[i], clName);
         if (match !== null) {
             return match;
         }
     }
     return null;
}

1

คุณสามารถดึงข้อมูลคลาสหลักได้โดยเพิ่มบรรทัดด้านล่าง หากคุณมี id มันจะง่ายกว่าด้วยgetElementById. อย่างไรก็ตาม

var parentNode = document.getElementsByClassName("progress__container")[0];

จากนั้นคุณสามารถใช้querySelectorAllบน<div>พาเรนต์เพื่อดึงข้อมูลที่ตรงกันทั้งหมดdivกับคลาส.progress__marker

var progressNodes = progressContainer.querySelectorAll('.progress__marker');

querySelectorAllจะดึงข้อมูลทุกอย่างdivด้วยคลาสของprogress__marker



-2

อืมมม ตัวอย่างนี้ใช้งานได้ใน IE8 แต่อาจจะใช้ไม่ได้ในกรณีที่คุณนำไปใช้กับวัตถุ ในกรณีของฉันคือตั้งค่า doc เป็นวัตถุ yui dom จากนั้นใช้ doc.getElementsByClassName นั่นคือเมื่อล้มเหลว แก้ไข: หรือบางทีฉันอาจไม่เข้าใจว่าวัตถุนั้นทำงานอย่างไรและเป็นเพียงวัตถุ Dom ธรรมดา?
spyderman4g63

@ spyderman4g63 รุ่น YUI ของเป็นวิธีการของgetElementsByClassName YAHOO.util.DomในกรณีของคุณการโทรจะมีลักษณะYAHOO.util.Dom.getElementsByClassName('four', 'span', 'test')ดังนี้ คุณควรอ่านเอกสารเพื่อทำความเข้าใจโดยละเอียดมากขึ้นว่าการโทรนั้นกำลังทำอะไรอยู่ รุ่นสั้น ๆ ว่าตอนนี้จะมองหาspanองค์ประกอบที่มีชั้นfourใต้องค์ประกอบ DOM ที่มีฐานะtest id
Hank Gay

@ spyderman4g63 ใช่ผลลัพธ์ของการgetโทรเป็นเพียงองค์ประกอบ DOM YUI ไม่ได้ใช้วิธีการแบบ 'ห่อทุกอย่างในวัตถุเฉพาะเฟรมเวิร์ก' แบบที่ jQuery ทำและมันก็ไม่ได้ปะติดปะต่อออบเจ็กต์เนทีฟเหมือน Prototype (ใช่ไหมฉันไม่ได้ยุ่งกับ Protoype ตลอดไป). ในแง่นี้ยูอิเหมือนโดโจมากกว่า
Hank Gay

-3

นี่คือวิธีที่ฉันทำโดยใช้ตัวเลือก YUI ขอบคุณคำแนะนำของ Hank Gay

notes = YAHOO.util.Dom.getElementsByClassName('four','span','test');

โดยที่ four = classname, span = ประเภทองค์ประกอบ / ชื่อแท็กและ test = รหัสหลัก


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