Comment obtenir un élément enfant par nom de classe?

131

J'essaye d'obtenir le span enfant qui a une classe = 4. Voici un exemple d'élément:

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

Les outils dont je dispose sont JS et YUI2. Je peux faire quelque chose comme ça:

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

//or

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

Ceux-ci ne fonctionnent pas dans IE. J'obtiens une erreur indiquant que l'objet (doc) ne prend pas en charge cette méthode ou propriété (getElementsByClassName). J'ai essayé quelques exemples d'implémentations multi-navigateurs de getElementsByClassName mais je n'ai pas pu les faire fonctionner et j'ai toujours cette erreur.

Je pense que ce dont j'ai besoin est un getElementsByClassName de navigateur croisé ou je dois utiliser doc.getElementsByTagName ('span') et faire une boucle jusqu'à ce que je trouve la classe 4. Je ne sais pas comment faire cela cependant.

spyderman4g63
la source
1
Assez drôle, le plus puissant querySelectorAllest pris en charge par IE 8+ alors qu'il getElementsByClassNamen'est pris en charge que par IE 9+. Si vous pouvez abandonner IE 7, vous pouvez l'utiliser en toute sécurité querySelectorAll('.4'). Au fait, 4est un nom de classe invalide.
Prinzhorn
@paritybit cette question ne fonctionne pas car elle utilise toujours getElementsByClassName et l'ancienne version d'IE ne semble pas prendre en charge cela. edit: Je suis désolé qu'il utilise le nom de la balise. Cela peut fonctionner.
spyderman4g63
@Prinzhorn Je n'ai pas l'utilitaire de sélection YUI2 disponible dans ce produit pour une raison quelconque.
spyderman4g63
@ spyderman4g63 Je n'ai rien dit de spécifique à YUI2. document.querySelectorAllest DOM et n'a rien à voir avec YUI
Prinzhorn

Réponses:

85

Utilisez doc.childNodespour parcourir chacun d'eux span, puis filtrez celui dont l' classNameéquivalent 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
la source
1
Le problème est que getElementsByClassName ne fonctionne pas dans IE8.
spyderman4g63
7
Ce code ne fonctionne pas si l'élément a plus d'une classe. Par exemple: si vous recherchez des éléments avec la classe "one" et que vos éléments ont la classe "one two three", cette fonction ne les trouvera pas.
Fran Verona le
3
@FranVerona Juste par curiosité, un simple "indexOf ('className')> -1" ne résoudrait-il pas le problème des classes multiples?
James Poulose
2
@JamesPoulose, ce ne serait pas le cas . Pensez à avoir un élément défini sur deux classes: petite et grande. thatElement.className renverrait une chaîne qui équivaut à "petit plus grand". Si vous recherchez une classe appelée big disant myElement.className.indexOf ("big") produira quelque chose d'inégal à négatif 1 bien que cela ne fasse pas partie de la classe. Si vous avez le contrôle à 100% de vos noms de classe, un tel correctif fonctionnerait, ce n'est tout simplement pas garanti, surtout lorsque vous écrivez du code qui va interagir avec du code sur lequel vous n'avez pas un contrôle total.
deadboy
Vous devriez utiliser une correspondance regex classNamecomme ceci: if(doc.childNode[i].className.match("\s*" + search_class + "\s*")où la variable search_classest le nom de classe que vous recherchez.
WebWanderer
130

Utiliser querySelector et querySelectorAll

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

IE9 et supérieur

;)

Alberto Clar Brines
la source
Merci pour votre solution intelligente!
Tai JinYuan le
1
Cela vérifie tous les descendants, pas seulement les enfants.
SUM1
47

La réponse acceptée ne vérifie que les enfants immédiats. Souvent, nous recherchons des descendants avec ce nom de classe.

Aussi, parfois nous voulons n'importe quel enfant qui contient un className.

Par exemple: <div class="img square"></div>doit correspondre à une recherche sur className "img", même si son exact className n'est pas "img".

Voici une solution à ces deux problèmes:

Trouvez la première instance d'un élément descendant avec la 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
la source
7
Nan. Je ne veux pas de tous les descendants, juste l'enfant comme la question posée.
Paul Draper
14
Petit. Votre commentaire était nécessaire. Heureux d'avoir aidé 13 autres personnes qui (comme moi) recherchent souvent des réponses similaires pour résoudre leur problème similaire, mais peut-être plus complexe ou général.
Augie Gardner
5
tnx, je pense que cette réponse convient à plus de cas d'utilisation
Boban Stojanovski
Pour mémoire, j'ai eu les deux cas d'utilisation, des descendants un peu plus souvent, mais je suis venu ici pour le cas d'utilisation des enfants.
SUM1
14

Utilisez element.querySelector (). Supposons: «myElement» est l'élément parent que vous avez déjà. 'sonClassName' est la classe de l'enfant que vous recherchez.

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

Pour plus d'informations, visitez: https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector

Hamza Dahmoun
la source
Pour une raison quelconque, j'ai dû utiliser let child = myElement.querySelector('sonClassName');dans mon cas
malat
Mais vous devez ajouter le point à côté du nom de la classe querySelector ('. SonClassName'), sinon il le gérera car sonClassName est un nom de tag et non un nom de classe
Hamza Dahmoun
10

Tu pourrais essayer:

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

ou

notes = doc.getElementsByTagName('*');
for (var i = 0; i < notes.length; i++) { 
    if (notes[i].getAttribute('class') == '4') {
    }
}
Korikulum
la source
1
Je me demandais si les navigateurs avaient enfin cette fonctionnalité sans nécessiter quelque chose comme jQuery, heureux de le voir. Si quelqu'un est curieux, on dirait qu'il est pris en charge dans la plupart des navigateurs modernes: developer.mozilla.org/en-US/docs/Web/API/Document/...
Liron Yahdav
8

Pour moi, il semble que vous vouliez la quatrième travée. Si tel est le cas, vous pouvez simplement le faire:

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

ou

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

Ce dernier garantit qu'il n'y a aucun nœud caché qui pourrait le gâcher.

Christian Jørgensen
la source
1
Merci, mais il y a une quantité variable d'éléments enfants.
spyderman4g63
1
Pour moi, il me semblait que la question était de toujours avoir le quatrième enfant, menant ainsi à ma réponse. Je suis bien sûr d'accord qu'une fonction pour obtenir n'importe quel type d'élément à n'importe quel index dans un autre élément serait meilleure, mais je n'ai pas interprété la question comme ça ... en relisant la question, je vois que j'ai totalement mal compris cependant: - )
Christian Jørgensen
TagNamec'est tout! Si simple.
Jacksonkr
J'utilise cette technique fréquemment pour obtenir le premier élément, par exemple document.getElementById ("test"). ChildNodes [0]
Louise Eggleton
@LouiseEggleton il y a .firstChildet .firstChildElementbien
YakovL
4

Mais sachez que les anciens navigateurs ne prennent pas en charge getElementsByClassName.

Ensuite, vous pouvez faire

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

Cela semble fonctionner, mais sachez qu'une classe HTML

  • Doit commencer par une lettre: AZ ou az
  • Peut être suivi de lettres (A-Za-z), de chiffres (0-9), de tirets ("-") et de traits de soulignement ("_")
Oriol
la source
3

Utilisez le nom de l'identifiant avec le getElementById, aucun #signe devant lui. Ensuite, vous pouvez obtenir les spannœuds enfants en utilisant getElementsByTagName, et les parcourir pour trouver celui avec la bonne classe:

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

Démo: http://jsfiddle.net/Guffa/xB62U/

Guffa
la source
Désolé, c'était une faute de frappe. Je peux sélectionner le conteneur div, mais je ne peux pas sélectionner les éléments enfants par nom de balise car cette fonction ne fonctionne pas dans ie8.
spyderman4g63
@ spyderman4g63: La getElementsByTagNameméthode fonctionne dans IE 8. Elle est prise en charge depuis IE 5.5. developer.mozilla.org/en-US/docs/DOM/…
Guffa
3

À mon avis, chaque fois que vous le pouvez, vous devez utiliser Array et ses méthodes. Ils sont beaucoup, beaucoup plus rapides que de boucler sur tout le DOM / wrapper, ou de pousser des éléments dans un tableau vide. La majorité des solutions présentées ici, vous pouvez appeler Naive comme décrit ici (excellent article btw):

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

Ma solution : (aperçu en direct sur 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
})

la source
1

La façon dont je vais faire cela en utilisant jquery est quelque chose comme ça.

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

Marselus Chia
la source
14
La question concerne javascript et non jQuery
Jya
1

Voici une solution récursive relativement simple. Je pense qu'une recherche en profondeur est appropriée ici. Cela renverra le premier élément correspondant à la classe trouvée.

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
la source
1

Vous pouvez récupérer la classe parente en ajoutant la ligne ci-dessous. Si vous aviez un identifiant, ce serait plus facile avec getElementById. Toutefois,

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

Ensuite, vous pouvez utiliser querySelectorAllsur le parent <div>pour récupérer tous les divs correspondants avec la classe.progress__marker

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

querySelectorAllira chercher tous divavec la classe deprogress__marker

Oussama Khawar
la source
1

Solution moderne

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

Documentation

Billizzard
la source
0

Mise à jour de juin 2018 vers ES6

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

YUI2 a une implémentation multi-navigateurs degetElementsByClassName .

Hank Gay
la source
Hmm. L'exemple fonctionne dans IE8, mais peut-être qu'il ne fonctionne pas dans le cas où vous l'appliquez à un objet. Dans mon cas, est défini doc comme un objet yui dom, puis utilisez doc.getElementsByClassName. C'est là que ça échoue. edit: ou peut-être que je ne comprends pas comment cet objet fonctionne et que ce n'est qu'un objet dom normal?
spyderman4g63
@ spyderman4g63 la version YUI de getElementsByClassNameest une méthode de YAHOO.util.Dom. Dans votre cas, l'appel ressemblerait à quelque chose comme YAHOO.util.Dom.getElementsByClassName('four', 'span', 'test'). Vous devriez probablement lire la documentation pour avoir une compréhension plus détaillée de ce que fait cet appel. La version courte est qu'il recherchera maintenant les spanéléments avec la classe foursous l'élément DOM avec testcomme son id.
Hank Gay
@ spyderman4g63 Oui, le résultat de l' getappel n'est qu'un élément DOM. YUI ne prend pas le genre d'approche globale `` envelopper tout dans un objet spécifique au framework '' que quelque chose comme jQuery fait, pas plus qu'il ne modifie les objets natifs comme Prototype (l'avez-vous fait? Je n'ai pas foiré avec Protoype pour toujours). À cet égard, YUI ressemble plus à Dojo.
Hank Gay
-3

Voici comment je l'ai fait en utilisant les sélecteurs YUI. Merci à la suggestion de Hank Gay.

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

où quatre = nom de classe, span = le type d'élément / nom de la balise et test = l'ID parent.

spyderman4g63
la source
-3

Utilisez à YAHOO.util.Dom.getElementsByClassName()partir d' ici .

John Lindal
la source