Bagaimana cara mendapatkan elemen anak berdasarkan nama kelas?

131

Saya mencoba untuk mendapatkan rentang anak yang memiliki kelas = 4. Berikut adalah contoh elemen:

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

Alat yang saya miliki adalah JS dan YUI2. Saya dapat melakukan sesuatu seperti ini:

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

//or

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

Ini tidak berfungsi di IE. Saya mendapatkan kesalahan bahwa objek (doc) tidak mendukung metode atau properti ini (getElementsByClassName). Saya sudah mencoba beberapa contoh implementasi lintas browser dari getElementsByClassName tapi saya tidak bisa membuatnya bekerja dan masih mendapatkan kesalahan itu.

Saya pikir apa yang saya butuhkan adalah browser lintas getElementsByClassName atau saya perlu menggunakan doc.getElementsByTagName ('span') dan loop melalui sampai saya menemukan kelas 4. Saya tidak yakin bagaimana melakukannya.

spyderman4g63
sumber
1
Cukup lucu, semakin kuat querySelectorAlldidukung oleh IE 8+ sedangkan getElementsByClassNamehanya didukung oleh IE 9+. Jika Anda dapat menjatuhkan IE 7, Anda aman digunakan querySelectorAll('.4'). Omong-omong, 4adalah nama kelas yang tidak valid.
Prinzhorn
@paritybit pertanyaan itu tidak berfungsi karena masih menggunakan getElementsByClassName dan versi IE yang lebih lama sepertinya tidak mendukung itu. sunting: Saya menyesal menggunakan nama tag. Ini mungkin berhasil.
spyderman4g63
@Rinzhorn Saya tidak memiliki utilitas pemilih YUI2 yang tersedia dalam produk ini karena alasan tertentu.
spyderman4g63
@ spyderman4g63 Saya tidak berbicara tentang apa pun YUI2 spesifik. document.querySelectorAlladalah DOM dan tidak ada hubungannya dengan YUI
Prinzhorn

Jawaban:

85

Gunakan doc.childNodesuntuk beralih melalui masing-masing span, dan kemudian filter yang classNamesama 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;
    }        
}

João Silva
sumber
1
Masalahnya adalah getElementsByClassName tidak berfungsi di IE8.
spyderman4g63
7
Kode ini tidak berfungsi jika elemen memiliki lebih dari satu kelas. Misalnya: jika Anda mencari elemen dengan kelas "satu", dan elemen Anda memiliki kelas "satu dua tiga", fungsi ini tidak akan menemukannya.
Fran Verona
3
@FranVerona Karena penasaran, bukankah "indexOf ('className')> -1" yang sederhana dapat memecahkan masalah beberapa kelas?
James Poulose
2
@ JamesPoulose, tidak akan . Pertimbangkan untuk mengatur elemen ke dua kelas: kecil dan lebih besar. thatElement.className akan mengembalikan sebuah String yang sama dengan "kecil lebih besar". Jika Anda mencari kelas yang disebut big pepatah myElement.className.indexOf ("besar") akan menghasilkan sesuatu yang tidak sama dengan negatif 1 meskipun itu tidak benar-benar menjadi bagian dari kelas. Jika Anda memiliki kontrol 100% dari nama kelas Anda, perbaikan seperti itu akan berhasil, itu tidak dijamin, terutama ketika Anda menulis kode yang akan berinteraksi kode Anda tidak memiliki kendali penuh atas.
deadboy
Anda harus menggunakan kecocokan regex pada classNameseperti ini: di if(doc.childNode[i].className.match("\s*" + search_class + "\s*")mana variabel search_classadalah nama kelas yang Anda cari.
WebWanderer
130

Gunakan querySelector dan querySelectorAll

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

IE9 dan yang lebih tinggi

;)

Alberto Clar Brines
sumber
Terima kasih atas solusi cerdas Anda!
Tai JinYuan
1
Ini memeriksa semua keturunan, bukan hanya anak-anak.
SUM1
47

Jawaban yang diterima hanya memeriksa anak langsung. Seringkali kita mencari keturunan dengan nama kelas itu.

Juga, kadang-kadang kita menginginkan anak yang mengandung className.

Sebagai contoh: <div class="img square"></div>harus cocok dengan pencarian di className "img", meskipun itu benar className bukan "img".

Inilah solusi untuk kedua masalah ini:

Temukan instance pertama elemen turunan dengan kelas 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;
    }
Augie Gardner
sumber
7
Nggak. Saya tidak ingin semua keturunan, hanya anak seperti pertanyaan yang diajukan.
Paul Draper
14
Anak binatang. Komentar Anda perlu. Senangnya saya membantu 13 orang lain yang (seperti saya) sering mencari jawaban yang sama untuk menyelesaikan masalah mereka yang sama, tetapi mungkin lebih kompleks atau umum.
Augie Gardner
5
tnx, saya pikir jawaban ini lebih cocok dengan kasus penggunaan lainnya
Boban Stojanovski
Sebagai catatan, saya pernah menggunakan keduanya, keturunan sedikit lebih sering, tapi saya datang ke sini untuk kasing anak.
SUM1
14

Gunakan element.querySelector (). Mari kita asumsikan: 'myElement' adalah elemen induk yang sudah Anda miliki. 'sonClassName' adalah kelas anak yang Anda cari.

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

Untuk info lebih lanjut, kunjungi: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector

Hamza Dahmoun
sumber
Untuk beberapa alasan saya harus menggunakan let child = myElement.querySelector('sonClassName');dalam kasus saya
malat
Tapi Anda harus menambahkan titik di sebelah nama kelas querySelector ('. SonClassName'), jika tidak maka akan menanganinya karena sonClassName adalah nama tag bukan nama kelas
Hamza Dahmoun
10

Kamu bisa mencoba:

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

atau

notes = doc.getElementsByTagName('*');
for (var i = 0; i < notes.length; i++) { 
    if (notes[i].getAttribute('class') == '4') {
    }
}
Korikulum
sumber
1
Saya bertanya-tanya apakah browser akhirnya memiliki fungsi ini tanpa memerlukan sesuatu seperti jQuery, senang melihatnya. Jika ada yang ingin tahu, sepertinya didukung di sebagian besar peramban modern: developer.mozilla.org/en-US/docs/Web/API/Document/…
Liron Yahdav
8

Bagi saya sepertinya Anda menginginkan rentang keempat. Jika demikian, Anda bisa melakukan ini:

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

atau

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

Yang terakhir ini memastikan bahwa tidak ada node tersembunyi yang dapat mengacaukannya.

Christian Jørgensen
sumber
1
Terima kasih, tetapi ada sejumlah variabel elemen anak.
spyderman4g63
1
Bagi saya sepertinya pertanyaannya adalah untuk selalu mendapatkan anak ke empat, sehingga mengarah ke jawaban saya. Saya tentu saja setuju bahwa fungsi untuk mendapatkan jenis elemen apa pun pada indeks apa pun dalam elemen lain akan lebih baik, tetapi saya tidak menginterpretasikan pertanyaan seperti itu ... membaca pertanyaan lagi, saya melihat bahwa saya benar-benar salah paham meskipun: - )
Christian Jørgensen
TagNameitu dia! Sangat sederhana.
Jacksonkr
Saya sering menggunakan teknik ini untuk mendapatkan elemen pertama misalnya document.getElementById ("test"). ChildNodes [0]
Louise Eggleton
@ LououEggleton ada .firstChilddan .firstChildElementmeskipun
YakovL
4

Namun ketahuilah bahwa browser lama tidak mendukung getElementsByClassName.

Lalu, Anda bisa melakukannya

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

Tampaknya ini berfungsi, tetapi perlu diperhatikan bahwa kelas HTML

  • Harus dimulai dengan surat: AZ atau az
  • Dapat diikuti oleh huruf (A-Za-z), digit (0-9), tanda hubung ("-"), dan garis bawah ("_")
Oriol
sumber
3

Gunakan nama id dengan getElementById, tanpa #tanda sebelum itu. Kemudian Anda bisa mendapatkan spansimpul anak menggunakan getElementsByTagName, dan loop melalui mereka untuk menemukan satu dengan kelas yang tepat:

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

Demo: http://jsfiddle.net/Guffa/xB62U/

Guffa
sumber
Maaf, itu salah ketik. Saya dapat memilih div wadah, tetapi tidak dapat memilih elemen turunan dengan nama tag karena fungsi itu tidak berfungsi di ie8.
spyderman4g63
@ spyderman4g63: getElementsByTagNameMetode ini bekerja di IE 8. Ini didukung sejauh IE 5.5. developer.mozilla.org/en-US/docs/DOM/…
Guffa
3

Menurut pendapat saya, setiap kali Anda bisa, Anda harus menggunakan Array dan metodenya. Mereka jauh, jauh lebih cepat daripada perulangan seluruh DOM / pembungkus, atau mendorong barang ke array kosong. Sebagian besar solusi yang disajikan di sini Anda dapat menghubungi Naif seperti yang dijelaskan di sini (artikel hebat btw):

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

Solusi saya : (pratinjau langsung tentang 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
})

sumber
1

Cara saya akan melakukan ini menggunakan jquery adalah sesuatu seperti ini ..

var tertargetchild = $ ("# test"). children (). find ("span.four");

Marselus Chia
sumber
14
pertanyaan adalah tentang javascript bukan jQuery
Jya
1

Berikut ini adalah solusi rekursif yang relatif sederhana. Saya pikir pencarian luas-pertama cocok di sini. Ini akan mengembalikan elemen pertama yang cocok dengan kelas yang ditemukan.

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;
}
Yer
sumber
1

Anda dapat mengambil kelas induk dengan menambahkan baris di bawah ini. Jika Anda memiliki id, akan lebih mudah dengan getElementById. Meskipun begitu,

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

Kemudian Anda dapat menggunakan querySelectorAllpada induk <div>untuk mengambil semua kecocokan divdengan kelas.progress__marker

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

querySelectorAllakan mengambil setiap divdengan kelasprogress__marker

Osama Khawar
sumber
1

Solusi modern

const context = document.getElementById('context');
const selected = context.querySelectorAll(':scope > div');

dokumentasi

Billizzard
sumber
0

Juni 2018 memperbarui ke ES6

    const doc = document.getElementById('test');
    let notes = null;
    for (const value of doc) {
        if (value.className === '4') {
            notes = value;
            break;
        }    
    }
Christopher Grigg
sumber
-2

YUI2 memiliki implementasi lintas browsergetElementsByClassName .

Hank Gay
sumber
Hmm. Contoh ini berfungsi di IE8, tapi mungkin tidak berfungsi jika Anda menerapkannya pada objek. Dalam kasus saya ditetapkan doc sebagai objek yui dom dan kemudian gunakan doc.getElementsByClassName. Saat itulah gagal. edit: atau mungkin saya tidak mengerti bagaimana objek itu bekerja dan itu hanya objek dom normal?
spyderman4g63
@ spyderman4g63 versi YUI getElementsByClassNameadalah metode YAHOO.util.Dom. Dalam kasus Anda, panggilan akan terlihat seperti YAHOO.util.Dom.getElementsByClassName('four', 'span', 'test'). Anda mungkin harus membaca dokumen untuk mendapatkan pemahaman yang lebih terperinci tentang apa yang dilakukan panggilan itu. Versi pendek adalah bahwa sekarang akan mencari spanelemen dengan kelas fourbawah elemen DOM dengan testsebagai yang id.
Hank Gay
@ spyderman4g63 Ya, hasil getpanggilan hanya elemen DOM. YUI tidak mengambil pendekatan seluruh penjualan 'membungkus semuanya dalam kerangka-objek khusus' yang dilakukan oleh sesuatu seperti jQuery, juga tidak melakukan patch-patch objek asli seperti Prototype (apakah? Saya belum mengacaukan w / Protoype selamanya). Dalam hal ini, YUI lebih seperti Dojo.
Hank Gay
-3

Ini adalah bagaimana saya melakukannya menggunakan penyeleksi YUI. Terima kasih atas saran Hank Gay.

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

di mana empat = classname, span = jenis elemen / nama tag, dan test = id induk.

spyderman4g63
sumber
-3

Gunakan YAHOO.util.Dom.getElementsByClassName()dari sini .

John Lindal
sumber