Jak uzyskać element potomny według nazwy klasy?

131

Próbuję uzyskać rozpiętość podrzędną, która ma klasę = 4. Oto przykładowy element:

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

Dostępne narzędzia to JS i YUI2. Mogę zrobić coś takiego:

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

//or

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

Te nie działają w IE. Pojawia się błąd, że obiekt (doc) nie obsługuje tej metody lub właściwości (getElementsByClassName). Wypróbowałem kilka przykładów implementacji getElementsByClassName w różnych przeglądarkach, ale nie mogłem ich uruchomić i nadal otrzymuję ten błąd.

Myślę, że to, czego potrzebuję, to getElementsByClassName w różnych przeglądarkach lub muszę użyć doc.getElementsByTagName ('span') i zapętlić, dopóki nie znajdę klasy 4. Nie jestem jednak pewien, jak to zrobić.

spyderman4g63
źródło
1
Co zabawne, mocniejszy querySelectorAlljest obsługiwany przez IE 8+, podczas gdy getElementsByClassNamejest obsługiwany tylko przez IE 9+. Jeśli możesz upuścić IE 7, możesz bezpiecznie używać querySelectorAll('.4'). Nawiasem mówiąc, 4to nieprawidłowa nazwa klasy.
Prinzhorn
@paritybit to pytanie nie działa, ponieważ nadal używa getElementsByClassName, a starsza wersja IE nie wydaje się tego obsługiwać. edycja: Przykro mi, że używa nazwy tagu. To może zadziałać.
spyderman4g63
@Prinzhorn Z jakiegoś powodu nie mam narzędzia selektora YUI2 dostępnego w tym produkcie.
spyderman4g63
@ spyderman4g63 Nie mówiłem o niczym szczególnym YUI2. document.querySelectorAlljest DOM i nie ma nic wspólnego z YUI
Prinzhorn,

Odpowiedzi:

85

Użyj doc.childNodesdo iteracji po każdym span, a następnie odfiltruj ten, którego classNamerówna się 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;
    }        
}

Wcześniejsze

João Silva
źródło
1
Problem polega na tym, że getElementsByClassName nie działa w IE8.
spyderman4g63
7
Ten kod nie działa, jeśli element ma więcej niż jedną klasę. Na przykład: jeśli szukasz elementów z klasą „jeden”, a Twoje elementy mają klasę „jeden, dwa, trzy”, ta funkcja ich nie znajdzie.
Fran Verona,
3
@FranVerona Tak z ciekawości, czy prosty „indexOf ('className')> -1” nie rozwiązałby problemu z wieloma klasami?
James Poulose
2
@JamesPoulose, nie byłoby . Rozważ ustawienie elementu na dwie klasy: małą i większą. thatElement.className zwróci ciąg znaków równy „mały większy”. Jeśli szukasz klasy o nazwie duże, powiedzenie myElement.className.indexOf ("duże") spowoduje powstanie czegoś nierównego do minus 1, mimo że w rzeczywistości nie jest częścią tej klasy. Jeśli masz 100% kontrolę nad nazwami swoich klas, taka poprawka zadziała, po prostu nie jest gwarantowana, zwłaszcza gdy piszesz kod, który ma wchodzić w interakcje z kodem, nad którym nie masz całkowitej kontroli.
deadboy
Powinieneś użyć dopasowania wyrażenia regularnego w classNamepodobny sposób: if(doc.childNode[i].className.match("\s*" + search_class + "\s*")gdzie zmienna search_classjest nazwą klasy, której szukasz.
WebWanderer
130

Użyj querySelector i querySelectorAll

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

IE9 i nowsze

;)

Solanki Alberto Clar
źródło
Dzięki za sprytne rozwiązanie!
Tai JinYuan
1
To sprawdza dla wszystkich potomków, nie tylko dzieci.
SUM 1
47

Zaakceptowana odpowiedź dotyczy tylko najbliższych dzieci. Często szukamy potomków o tej nazwie klasy.

Czasami też chcemy, aby każde dziecko zawierało className.

Na przykład: <div class="img square"></div>powinno pasować do wyszukiwania w className „img”, mimo że dokładna nazwa klasy to nie „img”.

Oto rozwiązanie obu tych problemów:

Znajdź pierwsze wystąpienie elementu podrzędnego z klasą 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
źródło
7
Nie. I nie chcą wszystkich potomków, podobnie jak dziecko zadawane pytania.
Paul Draper,
14
Szczenię. Twój komentarz był konieczny. Cieszę się, że pomogłem 13 innym osobom, które (tak jak ja) często szukają podobnych odpowiedzi, aby rozwiązać podobny, ale być może bardziej złożony lub ogólny problem.
Augie Gardner,
5
tnx, myślę, że odpowiedź garnitury więcej przypadków użycia
Boban Stojanovski
Dla przypomnienia, miałem oba przypadki użycia, potomków nieco częściej, ale przyszedłem tutaj po przypadek użycia dziecka.
SUM 1
14

Użyj elementu.querySelector (). Załóżmy: „myElement” jest elementem nadrzędnym, który już masz. „sonClassName” to klasa dziecka, którego szukasz.

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

Aby uzyskać więcej informacji, odwiedź: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector

Hamza Dahmoun
źródło
Z jakiegoś powodu musiałem użyć let child = myElement.querySelector('sonClassName');w moim przypadku
malatu
Ale musisz dodać kropkę obok nazwy klasy querySelector ('. SonClassName'), w przeciwnym razie będzie to obsługiwać tak, jak sonClassName to nazwa tagu, a nie nazwa klasy
Hamza Dahmoun
10

Możesz spróbować:

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

lub

notes = doc.getElementsByTagName('*');
for (var i = 0; i < notes.length; i++) { 
    if (notes[i].getAttribute('class') == '4') {
    }
}
Korikulum
źródło
1
Zastanawiałem się, czy przeglądarki wreszcie mają tę funkcjonalność bez konieczności posiadania czegoś takiego jak jQuery, ciesząc się, że to widzę. Jeśli ktoś jest ciekawy, wygląda na to, że jest obsługiwany w większości nowoczesnych przeglądarek: developer.mozilla.org/en-US/docs/Web/API/Document/ ...
Liron Yahdav
8

Wydaje mi się, że chcesz czwartego przęsła. Jeśli tak, możesz to zrobić:

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

lub

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

Ta ostatnia zapewnia, że ​​nie ma żadnych ukrytych węzłów, które mogłyby to zepsuć.

Christian Jørgensen
źródło
1
Dzięki, ale istnieje różna liczba elementów podrzędnych.
spyderman4g63
1
Wydawało mi się, że chodzi o to, aby zawsze mieć dziecko z czwartej grupy, co prowadziło do mojej odpowiedzi. Oczywiście zgadzam się, że funkcja pobierająca dowolny typ elementu w jakimkolwiek indeksie w innym elemencie byłaby lepsza, ale nie zinterpretowałem tego pytania w ten sposób ... ponownie czytając pytanie, widzę, że całkowicie źle zrozumiałem: - )
Christian Jørgensen
TagNameOtóż ​​to! Tak prosty.
Jacksonkr
Często używam tej techniki, aby uzyskać pierwszy element, np. Document.getElementById ("test"). ChildNodes [0]
Louise Eggleton
@LouiseEggleton jest .firstChildi .firstChildElementchociaż
YakovL
4

Należy jednak pamiętać, że stare przeglądarki nie obsługują getElementsByClassName .

Wtedy możesz to zrobić

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

Wygląda na to, że działa, ale należy pamiętać, że klasa HTML

  • Musi zaczynać się od litery: AZ lub az
  • Mogą po nim występować litery (A-Za-z), cyfry (0-9), łączniki („-”) i podkreślenia („_”)
Oriol
źródło
3

Użyj nazwy identyfikatora getElementByIdbez #znaku przed nim. Następnie możesz pobrać spanwęzły potomne za pomocą getElementsByTagNamei zapętlić je, aby znaleźć ten z odpowiednią klasą:

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
źródło
Przepraszamy, to # to literówka. Mogę wybrać element div kontenera, ale nie mogę wybrać elementów podrzędnych według nazwy tagu, ponieważ ta funkcja nie działa w ie8.
spyderman4g63
@ spyderman4g63: getElementsByTagNameMetoda działa w IE 8. Jest obsługiwana już od IE 5.5. developer.mozilla.org/en-US/docs/DOM/…
Guffa
3

Moim zdaniem za każdym razem, gdy możesz, powinieneś użyć Array i jego metod. Są dużo, dużo szybsze niż zapętlenie całego DOM / wrappera lub wypychanie rzeczy do pustej tablicy. Większość przedstawionych tutaj rozwiązań można nazwać Naive, jak opisano tutaj (przy okazji świetny artykuł):

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

Moje rozwiązanie : (podgląd na żywo na 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
})

źródło
1

Sposób, w jaki zrobię to za pomocą jquery, wygląda mniej więcej tak.

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

Marselus Chia
źródło
14
pytanie dotyczy javascript, a nie jQuery
Jya
1

Oto stosunkowo proste rozwiązanie rekurencyjne. Myślę, że wyszukiwanie wszerz jest tutaj odpowiednie. To zwróci pierwszy element pasujący do znalezionej klasy.

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;
}
Jer
źródło
1

Możesz pobrać klasę nadrzędną, dodając poniższy wiersz. Gdybyś miał identyfikator, byłoby łatwiej z getElementById. Niemniej jednak,

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

Następnie możesz użyć querySelectorAllna rodzicu, <div>aby pobrać wszystkie pasujące divpliki z klasą.progress__marker

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

querySelectorAllpobierze każdy divz klasąprogress__marker

Osama Khawar
źródło
1

Nowoczesne rozwiązanie

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

dokumentacja

Billizzard
źródło
0

Aktualizacja ES6 z czerwca 2018 r

    const doc = document.getElementById('test');
    let notes = null;
    for (const value of doc) {
        if (value.className === '4') {
            notes = value;
            break;
        }    
    }
Christopher Grigg
źródło
-2

YUI2 ma implementację w różnych przeglądarkachgetElementsByClassName .

Hank Gay
źródło
Hmm. Przykład działa w IE8, ale może nie zadziała w przypadku zastosowania go do obiektu. W moim przypadku ustaw doc jako obiekt yui dom, a następnie użyj doc.getElementsByClassName. Wtedy to zawodzi. edit: a może nie rozumiem, jak działa ten obiekt i jest to zwykły obiekt dom?
spyderman4g63
@ spyderman4g63 wersja YUI getElementsByClassNamejest metodą YAHOO.util.Dom. W Twoim przypadku połączenie wyglądałoby mniej więcej tak YAHOO.util.Dom.getElementsByClassName('four', 'span', 'test'). Prawdopodobnie powinieneś przeczytać dokumentację, aby uzyskać bardziej szczegółowe informacje na temat tego, co robi ta rozmowa. Krótka wersja jest taka, że ​​będzie teraz szukał spanelementów z klasą fourpod elementem DOM z testjako id.
Hank Gay
@ spyderman4g63 Tak, wynikiem getwywołania jest tylko element DOM. YUI nie przyjmuje podejścia polegającego na `` zawijaniu wszystkiego w obiekt specyficzny dla frameworka '', jak robi to coś takiego jak jQuery, ani nie naprawia natywnych obiektów, jak robi to Prototype (prawda? na zawsze). Pod tym względem YUI bardziej przypomina Dojo.
Hank Gay
-3

Oto jak to zrobiłem za pomocą selektorów YUI. Dzięki sugestii Hanka Gay'a.

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

gdzie cztery = nazwa klasy, span = typ elementu / nazwa tagu, a test = identyfikator nadrzędny.

spyderman4g63
źródło
-3

Skorzystaj YAHOO.util.Dom.getElementsByClassName()z tutaj .

John Lindal
źródło