Como obter o elemento filho pelo nome da classe?

131

Estou tentando obter a extensão filho que tem uma classe = 4. Aqui está um elemento de exemplo:

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

As ferramentas que tenho disponíveis são JS e YUI2. Eu posso fazer algo assim:

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

//or

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

Estes não funcionam no IE. Eu recebo um erro que o objeto (doc) não suporta esse método ou propriedade (getElementsByClassName). Eu tentei alguns exemplos de implementações entre navegadores de getElementsByClassName, mas não consegui fazê-las funcionar e ainda assim recebi esse erro.

Eu acho que o que eu preciso é um getElementsByClassName entre navegadores ou preciso usar doc.getElementsByTagName ('span') e percorrer até encontrar a classe 4. No entanto, não tenho certeza de como fazer isso.

spyderman4g63
fonte
1
Engraçado, o mais poderoso querySelectorAllé suportado pelo IE 8+, enquanto o getElementsByClassNameIE 9+ é suportado apenas. Se você pode largar o IE 7, é seguro usá-lo querySelectorAll('.4'). A propósito, 4é um nome de classe inválido.
Prinzhorn 28/08/2012
@paritybit essa pergunta não funciona porque ainda utiliza getElementsByClassName e a versão mais antiga do IE não parece suportar isso. edit: desculpe, ele usa o nome da tag. Isso pode funcionar.
spyderman4g63
@Prinzhorn Não tenho o utilitário seletor YUI2 disponível neste produto por algum motivo.
Spyderman4g63
@ spyderman4g63 Não falei sobre nada específico do YUI2. document.querySelectorAllé DOM e não tem nada a ver com YUI
Prinzhorn

Respostas:

85

Use doc.childNodespara percorrer cada um spane, em seguida, filtre aquele cujo classNameé igual a 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;
    }        
}

O que outras pessoas estão dizendo

João Silva
fonte
1
O problema é que getElementsByClassName não funciona no IE8.
Spyderman4g63
7
Este código não funciona se o elemento tiver mais de uma classe. Por exemplo: se você estiver procurando por elementos com a classe "one" e seus elementos tiverem a classe "one two three", essa função não os encontrará.
Fran Verona
3
@FranVerona Por curiosidade, um simples "indexOf ('className')> -1" não resolveria o problema de várias classes?
James Poulose
2
@JamesPoulose, não seria . Considere ter um elemento definido para duas classes: pequena e maior. thatElement.className retornaria uma String igual a "pequeno maior". Se você estiver procurando por uma classe chamada big, dizendo que myElement.className.indexOf ("big") produzirá algo desigual para 1 negativo, apesar de não fazer parte da classe. Se você tem 100% de controle de seus nomes de classe, essa correção funcionaria, mas não é garantido, especialmente quando você está escrevendo um código que irá interagir com um código que você não tem controle total.
deadboy
Você deve usar uma correspondência de regex da seguinte classNamemaneira: if(doc.childNode[i].className.match("\s*" + search_class + "\s*")onde a variável search_classé o nome da classe que você está procurando.
WebWanderer 18/03/16
130

Use querySelector e querySelectorAll

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

IE9 e superior

;)

Alberto Clar Brines
fonte
Obrigado pela sua solução inteligente!
Tai JinYuan
1
Isso verifica todos os descendentes, não apenas crianças.
SUM1 15/06
47

A resposta aceita apenas verifica filhos imediatos. Muitas vezes, procuramos descendentes com esse nome de classe.

Além disso, às vezes queremos qualquer filho que contenha um className.

Por exemplo: <div class="img square"></div>deve corresponder a uma pesquisa no className "img", mesmo que o className exato não seja "img".

Aqui está uma solução para esses dois problemas:

Encontre a primeira instância de um elemento descendente com a classe 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
fonte
7
Não. Eu não quero que todos os descendentes, apenas a criança como a pergunta.
Paul Draper
14
Whelp. Seu comentário foi necessário. Ainda bem que ajudei outras 13 pessoas que (como eu) costumam procurar respostas semelhantes para resolver seu problema semelhante, mas talvez mais complexo ou geral.
Augie Gardner
5
tnx, eu acho que esta resposta ternos mais casos de uso
Boban Stojanovski
Para constar, eu tive dois casos de uso, descendentes um pouco mais frequentemente, mas vim aqui para o caso de uso infantil.
SUM1 15/06
14

Use element.querySelector (). Vamos supor: 'myElement' é o elemento pai que você já possui. 'sonClassName' é a classe do filho que você está procurando.

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

Para mais informações, visite: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector

Hamza Dahmoun
fonte
Por alguma razão eu tive que usar let child = myElement.querySelector('sonClassName');no meu caso
malat 10/04
Mas você deve adicionar o ponto ao lado do nome da classe querySelector ('. SonClassName'), caso contrário, ele será tratado como sonClassName é um nome de marca e não um nome de classe
Hamza Dahmoun
10

Você poderia tentar:

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

ou

notes = doc.getElementsByTagName('*');
for (var i = 0; i < notes.length; i++) { 
    if (notes[i].getAttribute('class') == '4') {
    }
}
Korikulum
fonte
1
Eu queria saber se os navegadores finalmente tinham essa funcionalidade sem precisar de algo como jQuery, feliz em vê-la. Se alguém é curioso, parece que é suportado na maioria dos navegadores modernos: developer.mozilla.org/en-US/docs/Web/API/Document/...
Liron Yahdav
8

Para mim, parece que você quer o quarto período. Nesse caso, você pode apenas fazer o seguinte:

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

ou

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

Este último garante que não haja nós ocultos que possam atrapalhar.

Christian Jørgensen
fonte
1
Obrigado, mas há uma quantidade variável de elementos filhos.
Spyderman4g63
1
Para mim, parecia que a pergunta era sempre ter o quarto filho, levando à minha resposta. É claro que concordo que uma função para obter qualquer tipo de elemento em qualquer índice dentro de um outro elemento seria melhor, mas não interpretei a questão dessa maneira ... lendo a pergunta novamente, vejo que eu entendi totalmente: )
Christian Jørgensen
TagNameé isso aí! Tão simples.
Jacksonkr
Eu uso essa técnica frequentemente para obter o primeiro elemento, por exemplo, document.getElementById ("test"). ChildNodes [0]
Louise Eggleton
@LouiseEggleton há .firstChilde .firstChildElementembora
YakovL
4

Mas lembre-se de que navegadores antigos não suportam getElementsByClassName .

Então você pode fazer

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

Parece que funciona, mas saiba que uma classe HTML

  • Deve começar com uma letra: AZ ou az
  • Pode ser seguido por letras (A-Za-z), dígitos (0-9), hífens ("-") e sublinhados ("_")
Oriol
fonte
3

Use o nome do ID com o sinal getElementByIdsem #sinal antes dele. Em seguida, você pode obter os spannós filhos usando getElementsByTagNamee percorrê-los para encontrar aquele com a classe certa:

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

Demonstração: http://jsfiddle.net/Guffa/xB62U/

Guffa
fonte
Desculpe, foi um erro de digitação. Posso selecionar a div do contêiner, mas não posso selecionar os elementos filhos pelo nome da tag, porque essa função não está funcionando no ie8.
Spyderman4g63
@ spyderman4g63: O getElementsByTagNamemétodo funciona no IE 8. Ele é suportado desde o IE 5.5. developer.mozilla.org/pt-BR/docs/DOM/…
Guffa
3

Na minha opinião, sempre que puder, use Array e seus métodos. Eles são muito, muito mais rápidos do que percorrendo todo o DOM / wrapper ou empurrando coisas para uma matriz vazia. Maioria das soluções apresentadas aqui, você pode chamar Naive como descrito aqui (ótimo artigo entre):

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

Minha solução : (visualização ao vivo no 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
})

fonte
1

A maneira como farei isso usando jquery é algo como isto ..

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

Marselus Chia
fonte
14
pergunta é sobre javascript não jQuery
Jya
1

Aqui está uma solução recursiva relativamente simples. Eu acho que uma pesquisa pela primeira vez é apropriada aqui. Isso retornará o primeiro elemento correspondente à classe encontrada.

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
fonte
1

Você pode buscar a classe pai adicionando a linha abaixo. Se você tivesse um ID, seria mais fácil getElementById. Não obstante,

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

Em seguida, você pode usar querySelectorAllno pai <div>para buscar todos os divs correspondentes com a classe.progress__marker

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

querySelectorAllvai buscar todos divcom a classe deprogress__marker

Osama Khawar
fonte
1

Solução moderna

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

documentação

Billizzard
fonte
0

Atualização de junho de 2018 para ES6

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

O YUI2 possui uma implementação entre navegadores degetElementsByClassName .

Hank Gay
fonte
Hmm. O exemplo funciona no IE8, mas talvez não funcione no caso de você aplicá-lo a um objeto. No meu caso, é definido doc como um objeto yui dom e use doc.getElementsByClassName. É quando falha. edit: ou talvez eu não entenda como esse objeto funciona e é apenas um objeto dom normal?
Spyderman4g63
@ spyderman4g63 a versão YUI do getElementsByClassNameé um método de YAHOO.util.Dom. No seu caso, a ligação seria semelhante a YAHOO.util.Dom.getElementsByClassName('four', 'span', 'test'). Você provavelmente deve ler os documentos para obter uma compreensão mais detalhada do que essa chamada está fazendo. A versão curta é que ele agora vai procurar spanelementos com a classe foursob o elemento DOM com testcomo seu id.
Hank Gay
@ spyderman4g63 Sim, o resultado da getchamada é apenas um elemento DOM. A YUI não adota o tipo de abordagem 'embrulhar tudo em um objeto específico de estrutura' de venda inteira que algo como o jQuery faz, nem faz o patch de objetos nativos como o Prototype (não é? Não brinquei com o Protoype para sempre). Nesse aspecto, o YUI é mais parecido com o Dojo.
Hank Gay
-3

Aqui está como eu fiz isso usando os seletores YUI. Graças à sugestão de Hank Gay.

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

onde quatro = nome da classe, extensão = o tipo de elemento / nome do tag e test = o ID pai.

spyderman4g63
fonte
-3

Use YAHOO.util.Dom.getElementsByClassName()a partir daqui .

John Lindal
fonte