¿Cómo obtener el elemento hijo por nombre de clase?

131

Estoy tratando de obtener el span secundario que tiene una clase = 4. Aquí hay un elemento de ejemplo:

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

Las herramientas que tengo disponibles son JS y YUI2. Puedo hacer algo como esto:

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

//or

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

Estos no funcionan en IE. Recibo un error de que el objeto (doc) no admite este método o propiedad (getElementsByClassName). He probado algunos ejemplos de implementaciones en varios navegadores de getElementsByClassName, pero no pude hacer que funcionen y todavía recibí ese error.

Creo que lo que necesito es un getElementsByClassName de navegador cruzado o necesito usar doc.getElementsByTagName ('span') y recorrer hasta encontrar la clase 4. Sin embargo, no estoy seguro de cómo hacerlo.

spyderman4g63
fuente
1
Curiosamente, querySelectorAllIE 8+ getElementsByClassNamees el más potente, mientras que solo es compatible con IE 9+. Si puede soltar IE 7, es seguro usarlo querySelectorAll('.4'). Por cierto, 4es un nombre de clase no válido.
Prinzhorn
@paritybit esa pregunta no funciona porque todavía utiliza getElementsByClassName y la versión anterior de IE no parece admitir eso. editar: lo siento, usa el nombre de la etiqueta. Esto puede funcionar.
spyderman4g63
@Prinzhorn No tengo la utilidad de selector YUI2 disponible en este producto por alguna razón.
spyderman4g63
@ spyderman4g63 No hablé de nada específico de YUI2. document.querySelectorAlles DOM y no tiene nada que ver con YUI
Prinzhorn

Respuestas:

85

Use doc.childNodespara iterar a través de cada uno spany luego filtre el que sea classNameigual 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;
    }        
}

João Silva
fuente
1
El problema es que getElementsByClassName no funciona en IE8.
spyderman4g63
77
Este código no funciona si el elemento tiene más de una clase. Por ejemplo: si está buscando elementos con la clase "uno" y sus elementos tienen la clase "uno dos tres", esta función no los encontrará.
Fran Verona
3
@FranVerona Solo por curiosidad, ¿un simple "indexOf ('className')> -1" no resolvería el problema de clases múltiples?
James Poulose
2
@JamesPoulose, no lo haría . Considere tener un elemento establecido en dos clases: pequeño y más grande. thatElement.className devolvería una cadena que equivale a "pequeño más grande". Si está buscando una clase llamada big diciendo myElement.className.indexOf ("big") producirá algo desigual al negativo 1 a pesar de que en realidad no es parte de la clase. Si tienes el 100% de control de los nombres de tus clases, tal solución funcionaría, simplemente no está garantizado, especialmente cuando escribes código que va a interactuar con código sobre el que no tienes control total.
deadboy
Debería usar una coincidencia de expresiones regulares de la classNamemisma manera: if(doc.childNode[i].className.match("\s*" + search_class + "\s*")donde la variable search_classes el nombre de clase que está buscando.
WebWanderer
130

Utilice querySelector y querySelectorAll

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

IE9 y superior

;)

Alberto Clar Brines
fuente
¡Gracias por su solución inteligente!
Tai JinYuan
1
Esto verifica todos los descendientes, no solo los niños.
SUM1
47

La respuesta aceptada solo verifica a los niños inmediatos. Muchas veces estamos buscando descendientes con ese nombre de clase.

Además, a veces queremos cualquier hijo que contenga un className.

Por ejemplo: <div class="img square"></div>debe coincidir con una búsqueda en className "img", aunque sea exactamente className no es "img".

Aquí hay una solución para ambos problemas:

Encuentra la primera instancia de un elemento descendiente con la clase 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
fuente
77
No Yo no quiero que todos los descendientes, sólo el niño como la pregunta formulada.
Paul Draper
14
Parir. Tu comentario fue necesario. Me alegra haber ayudado a otras 13 personas que (como yo) a menudo buscan respuestas similares para resolver su problema similar, pero quizás más complejo o general.
Augie Gardner
55
tnx, creo que esta respuesta se adapta a más casos de uso
Boban Stojanovski
Para el registro, he tenido ambos casos de uso, descendientes un poco más a menudo, pero vine aquí por el caso de uso infantil.
SUM1
14

Use element.querySelector (). Supongamos: 'myElement' es el elemento padre que ya tiene. 'sonClassName' es la clase del niño que está buscando.

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

Para obtener más información, visite: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector

Hamza Dahmoun
fuente
Por alguna razón tuve que usar let child = myElement.querySelector('sonClassName');en mi caso
malat
Pero debe agregar el punto al lado del nombre de clase querySelector ('. SonClassName'), de lo contrario lo manejará como sonClassName es un nombre de etiqueta, no un nombre de clase
Hamza Dahmoun
10

Tu podrías intentar:

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

o

notes = doc.getElementsByTagName('*');
for (var i = 0; i < notes.length; i++) { 
    if (notes[i].getAttribute('class') == '4') {
    }
}
Korikulum
fuente
1
Me preguntaba si los navegadores finalmente tenían esta funcionalidad sin requerir algo como jQuery, me alegra verlo. Si alguien tiene curiosidad, parece que es compatible con la mayoría de los navegadores modernos: developer.mozilla.org/en-US/docs/Web/API/Document/…
Liron Yahdav
8

Para mí parece que quieres el cuarto tramo. Si es así, puedes hacer esto:

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

o

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

Este último garantiza que no haya ningún nodo oculto que pueda estropearlo.

Christian Jørgensen
fuente
1
Gracias, pero hay una cantidad variable de elementos secundarios.
spyderman4g63
1
Para mí, parecía que la pregunta era siempre obtener el hijo del cuarto hijo, lo que lleva a mi respuesta. Por supuesto, estoy de acuerdo en que una función para obtener cualquier tipo de elemento en cualquier índice dentro de otro elemento sería mejor, pero no interpreté la pregunta así ... al leer la pregunta nuevamente, veo que entendí totalmente mal: )
Christian Jørgensen
TagName¡Eso es! Tan sencillo.
Jacksonkr
Utilizo esta técnica con frecuencia para obtener el primer elemento, por ejemplo, document.getElementById ("prueba"). ChildNodes [0]
Louise Eggleton
@LouiseEggleton hay .firstChildy .firstChildElementaunque
YakovL
4

Pero tenga en cuenta que los navegadores antiguos no son compatibles getElementsByClassName.

Entonces puedes hacer

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, pero tenga en cuenta que una clase HTML

  • Debe comenzar con una letra: AZ o az
  • Puede ir seguido de letras (A-Za-z), dígitos (0-9), guiones ("-") y guiones bajos ("_")
Oriol
fuente
3

Use el nombre de la identificación con getElementById, sin #signo antes. Luego puede spanusar los nodos secundarios getElementsByTagNamey recorrerlos para encontrar el que tenga la clase correcta:

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

Manifestación: http://jsfiddle.net/Guffa/xB62U/

Guffa
fuente
Lo siento, fue un error tipográfico. Puedo seleccionar el contenedor div, pero no puedo seleccionar los elementos secundarios por nombre de etiqueta porque esa función no funciona en ie8.
spyderman4g63
@ spyderman4g63: el getElementsByTagNamemétodo funciona en IE 8. Se admite desde IE 5.5. developer.mozilla.org/en-US/docs/DOM/…
Guffa
3

En mi opinión, cada vez que puedas, debes usar Array y sus métodos. Son mucho, mucho más rápidos que hacer un bucle en todo el DOM / contenedor, o empujar cosas en una matriz vacía. La mayoría de las soluciones presentadas aquí puede llamar a Naive como se describe aquí (gran artículo por cierto):

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

Mi solución : (vista previa en vivo en 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
})

fuente
1

La forma en que haré esto usando jquery es algo como esto ...

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

Marselus Chia
fuente
14
pregunta es sobre JavaScript, no jQuery
Jya
1

Aquí hay una solución recursiva relativamente simple. Creo que una búsqueda de amplitud es apropiada aquí. Esto devolverá el primer elemento que coincida con la clase que se encuentra.

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

Puede buscar la clase principal agregando la siguiente línea. Si tuviera una identificación, sería más fácil con getElementById. Sin embargo,

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

Luego puede usar querySelectorAllen el padre <div>para obtener todos los divs coincidentes con la clase.progress__marker

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

querySelectorAllbuscará todos divcon la clase deprogress__marker

Osama Khawar
fuente
1

Solución moderna

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

documentación

Billizzard
fuente
0

Actualización de junio de 2018 a ES6

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

YUI2 tiene una implementación de navegador cruzado degetElementsByClassName .

Hank Gay
fuente
Hmm El ejemplo funciona en IE8, pero tal vez no funcione en el caso de que lo aplique a un objeto. En mi caso, se establece doc como un objeto yui dom y luego uso doc.getElementsByClassName. Ahí es cuando falla. editar: ¿o tal vez no entiendo cómo funciona ese objeto y es solo un objeto dom normal?
spyderman4g63
@ spyderman4g63 la versión YUI de getElementsByClassNamees un método de YAHOO.util.Dom. En su caso, la llamada se vería algo así YAHOO.util.Dom.getElementsByClassName('four', 'span', 'test'). Probablemente debería leer los documentos para obtener una comprensión más detallada de lo que está haciendo esa llamada. La versión corta es que ahora buscará spanelementos con la clase fourdebajo del elemento DOM testcomo su id.
Hank Gay el
@ spyderman4g63 Sí, el resultado de la getllamada es solo un elemento DOM. YUI no toma el tipo de enfoque de venta completa de 'envolver todo en un objeto específico del marco' que hace algo como jQuery, ni hace parches de mono con objetos nativos como lo hace Prototype (¿no? en siempre). A este respecto, YUI es más como Dojo.
Hank Gay
-3

Así es como lo hice usando los selectores YUI. Gracias a la sugerencia de Hank Gay.

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

donde four = classname, span = el tipo de elemento / nombre de etiqueta, y test = la identificación principal

spyderman4g63
fuente
-3

Usar YAHOO.util.Dom.getElementsByClassName()desde aquí .

John Lindal
fuente