Alt düğümleri almanın en iyi yolu


233

Merak ediyorum, JavaScript herhangi bir öğeden ilk alt öğeyi almak için çeşitli yöntemler sunuyor, ama hangisi en iyisi? En iyisi, yani: davranışlar söz konusu olduğunda, tarayıcılar arası en uyumlu, en hızlı, en kapsamlı ve öngörülebilir. Takma ad olarak kullandığım yöntemlerin / özelliklerin listesi:

var elem = document.getElementById('container');
var child = elem.children[0];
var child = elem.firstElementChild; // == children[0]

Bu her iki durumda da işe yarar:

var child = elem.childNodes[0]; // or childNodes[1], see below

Bu formlar veya <div>yineleme durumunda. Metin öğeleriyle karşılaşabilirsem:

var child = elem.childNodes; // treat as NodeList
var child = elem.firstChild;

Çalışabildiğim kadarıyla firstChild, NodeList'i kullanır childNodesve firstElementChildkullanır children. Bu varsayımı MDN referansına dayandırıyorum:

childNodeöğesi, öğe düğümünün ilk alt öğesine veya bir öğe nullyoksa başvurudır .

Hız açısından, eğer varsa, farkın hiçbir şeyin yanında olmayacağını tahmin ediyorum, çünkü firstElementChildetkili bir şekilde referanstır children[0]ve childrennesne zaten hafızadadır.

Beni fırlatan şey, childNodesnesnedir. Bir tablo elemanındaki bir forma bakmak için kullandım. İken childrenlisteleri tüm form elemanları, childNodesayrıca HTML kodundan boşluk içerecek şekilde görünüyor:

console.log(elem.childNodes[0]);
console.log(elem.firstChild);

Her iki günlük <TextNode textContent="\n ">

console.log(elem.childNodes[1]);
console.log(elem.children[0]);
console.log(elem.firstElementChild);

Tüm günlükler <input type="text">. Nasıl olur? Bir nesnenin "ham" HTML koduyla çalışmama izin verdiğini anlıyorum, diğeri DOM'ye yapışıyor, ancak childNodesöğe her iki düzeyde de çalışıyor gibi görünüyor.

İlk soruma geri dönmek için tahminim şu olurdu: En kapsamlı nesneyi istiyorsam, childNodesgitmenin yolu budur, ancak kapsamlı olması nedeniyle, istediğim öğeyi döndürmesi açısından en öngörülebilir olmayabilir / herhangi bir anda bekliyoruz. Çapraz tarayıcı desteği de bu durumda zor olabilir, ancak yanlış olabilirim.

Herkes elindeki nesneler arasındaki ayrımı açıklığa kavuşturabilir mi? Eğer ihmal edilebilir bir hız farkı varsa, ben de bilmek isterim. Eğer bunların hepsini yanlış görürsem, beni eğitmekten çekinmeyin.


Not: Lütfen, lütfen, JavaScript'i seviyorum, bu yüzden evet, bu tür şeylerle uğraşmak istiyorum. “JQuery sizin için bununla ilgileniyor” gibi cevaplar aradığım şey değil, dolayısıyla hayır etiket.


50
>> lütfen, lütfen, JavaScript'i seviyorum, bu yüzden evet, bu tür şeylerle uğraşmak istiyorum. 'jQuery sizin için bununla fırsatlar' gibi cevaplar aradığım şey bu değil << bu
upvotes

Yanıtlar:


211

Sanki onu düşünüyor gibisin. Sen arasındaki farkı gözlemledik childNodesve childrenyani childNodesederken, tamamen boşluk oluşan metin düğümlerinin dahil tüm düğümleri içerir childrenunsurlardır sadece alt düğümler topluluğudur. Gerçekten hepsi bu kadar.

Her iki koleksiyon hakkında da öngörülemeyen bir şey yok, ancak bilinmesi gereken birkaç sorun var:

  • IE <= 8 childNodes, diğer tarayıcılar eklerken yalnızca boşluk içeren metin düğümlerini içermez
  • IE <= 8 içerisindeki yorum düğümlerini childreniçerirken diğer tarayıcılarda yalnızca öğeler bulunur

children, firstElementChildVe arkadaşlar sadece unsurları sınırlı DOM filtrelenmiş bir görünüm sunan sadece kolaylıklar vardır.


Bir şey hala beni rahatsız ediyor olsa da, düşündüm: childNodes'un aldığı boşluk metin kodu aslında sadece yeni bir satır ve koddaki birkaç sekmedir. Bu XHTML doktrininden mi kaynaklanıyor? kod içindeki kodları yapılandırmak için boşluk ekleyerek çözülebilir mi?
Elias Van Ootegem

@EliasVanOotegem: Bu, doktrinle alakasız. Beyaz boşluk metin düğümleri, kaynakta göründükleri her yerde HTML ve XHTML için her zaman DOM'a (IE <9 hariç) dahil edilir. Genellikle iyi bir şeydir, ancak buna hazırlıklı değilseniz sizi yakalayabilir.
Tim Down

İşaretlememi böyle yazmaya yardımcı olur mu demek istedim <td\n\t>content</td>. XML'de yapabileceğiniz gibi, fazla boşlukların verilerin bir parçası (veya bu durumda DOM) olarak kabul edilmesini önlemek için. Neden bir etiketin içindeki boşluk DOM'a dahil edilir?
Elias Van Ootegem

@EliasVanOotegem: Oh, anlıyorum. Bir etiketin içindeki etiket adından sonraki beyaz boşluk yok sayılır, böylece böyle bir şey yapabilirsiniz. Bu tekniğin, tarayıcıların bazı öğeler arasında beyaz boşluk için küçük boşluklar eklemesini önlemek için hassas düzenlerde kullanıldığını gördüm.
Tim Down

2
@Christophe: Ah, doğru nokta, teşekkürler. Cevabıma bir not ekleyeceğim. childrenIE 4'te bir standart haline gelmeden veya diğer tarayıcılar tarafından benimsenmeden önce on yıl içinde ortaya çıktığı düşünüldüğünde, IE <8'in doğru ve diğer tarayıcıların yanlış olduğunu iddia edebilirsiniz.
Tim Down

23

firstElementChild, IE <9'da bulunmayabilir (yalnızca firstChild)

IE <9 firstChild ilkElementChild çünkü MS DOM (IE <9) boş metin düğümleri depolamıyor. Ancak bunu diğer tarayıcılarda yaparsanız boş metin düğümleri döndürürler ...

çözümüm

child=(elem.firstElementChild||elem.firstChild)

bu IE <9 bile ilk çocuğu verecektir


Bir elem.firstChildeleman düğümü değilse elem.firstElementChild, her zaman eleman düğümü olduğu için sonuçlar eski IE'lerde farklı olacaktır .
duri

Üzgünüm, ama tüm önemli tarayıcılarda ilk çocuğu nasıl alacağımı biliyorum. Bilmek istediğim, aralarındaki benzerlikleri ve farklılıkları daha iyi anlamak için farklı nesnelerin nasıl yapılandırıldığı. Daha sonra karıştırmak için üzgünüm
Elias Van Ootegem

1
firstElementChildIE olmayan tarayıcılarda da güvenli olmayabilir: Firefox yalnızca 3.5 sürümünde desteklemeye başladı.
Tim Down

Bu chrome, IE9 ve IE8 için çalışıyor, çünkü eğer firstElementChild varsa, diğer kontrol yürütülmez, aksi takdirde (eski IE) firstChild var ve firstEhickChild (IE <9) olmayan tarayıcı için bir eleman düğümüdür ) ... yine de merak ediyorum FF
neu-rah

1
Tim, bu bir şeyler nesnelerin googling zaman doğrudur bu geldi, iyi bir site bir süre içinde bir kez kontrol etmek
Elias Van Ootegem

20

Çapraz tarayıcı yapmanın yolu , ELEMENT_NODE ile childNodesalmak NodeList, daha sonra tüm düğümlerden oluşan bir dizi yapmak için kullanmaktır .nodeType

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    var childNodes = element.childNodes,
        children = [],
        i = childNodes.length;

    while (i--) {
        if (childNodes[i].nodeType == 1) {
            children.unshift(childNodes[i]);
        }
    }

    return children;
}

http://jsfiddle.net/s4kxnahu/

Lodash gibi bir yardımcı program kitaplığı kullanıyorsanız bu özellikle kolaydır :

/**
 * Return direct children elements.
 *
 * @param {HTMLElement}
 * @return {Array}
 */
function elementChildren (element) {
    return _.where(element.childNodes, {nodeType: 1});
}

Gelecek:

Sözde sınıfla querySelectorAllbirlikte kullanabilirsiniz :scope(seçicinin referans noktası olan öğeyle eşleşir):

parentElement.querySelectorAll(':scope > *');

Bu yazı yazıldığı sırada Chrome, Firefox ve Safari'de :scopedesteklenir .


: kapsam spesifikasyondan kaldırıldı . Gelecek bölümünü kaldırmalı mıyız ?
Thomas Marti

4

Sadece diğer cevaplara eklemek için, özellikle de <svg>unsurlarla uğraşırken hala dikkate değer farklılıklar vardır .

Her ikisini de kullandım .childNodesve alıcı tarafından teslim edilenlerle .childrençalışmayı tercih ettim .HTMLCollection.children

Bugün ancak, kullanırken başarısız IE / Edge ile sorunlarla karşılaştıysanız, .childrenbir de <svg>. İken .childrentemel HTML unsurları IE desteklenir, bu belge / doküman parçaları, desteklenmemektedir veya SVG öğeleri .

Benim için, .childNodes[n]endişelenecek yabancı metin düğümlerim olmadığından , gerekli öğeleri kolayca yakalayabildim . Aynı şeyi yapabilirsiniz, ancak yukarıda başka bir yerde belirtildiği gibi, beklenmedik unsurlarla karşılaşabileceğinizi unutmayın.

Bu .childrenmodern IE üzerinde js başka bir yerde neden çalışıyor ve belge veya SVG öğeleri başarısız neden anlamaya çalışırken başlarını tırmalamak için yararlı olduğunu umuyoruz .


3

Hey çocuklar beyaz alanın sizi kandırmasına izin vermiyor. bunu bir konsol tarayıcısında test edin. yerel javascript kullanın. Burada ve aynı sınıfa sahip iki 'ul' seti ile örnek. Beyaz alandan kaçınmak için 'ul' listenizin bir satırda olmasına gerek yoktur, sadece beyaz alanın üzerine atlamak için dizi sayınızı kullanın.

querySelector()O zaman childNodes[]js keman bağlantısı ile beyaz alanı nasıl dolaşırsınız: https://jsfiddle.net/aparadise/56njekdo/

var y = document.querySelector('.list');
var myNode = y.childNodes[11].style.backgroundColor='red';

<ul class="list">
    <li>8</li>
    <li>9</li>
    <li>100</li>
</ul>

<ul class="list">
    <li>ABC</li>
    <li>DEF</li>
    <li>XYZ</li>
</ul>

Aşağı oylamam değil, ama sanırım biri aşağı oy verdi çünkü: a) Bu soru 4 yaşında, document.querySelectoro zamanlar iyi desteklenmedi. b) Soru temel olarak, aralarındaki childrenve childNodes içteki farklılıkların ne olduğunu sormak , ki bu ne zaman diğerinden daha fazla seçileceğidir. ve c) Çünkü, soruda gösterildiği childNodes gibi : boşluk düğümleri içerir, childreniçermez ...
Elias Van Ootegem
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.