Les outils de navigation du DOM sont trĂšs pratiques quand les Ă©lĂ©ments sont proches les uns des autres. Mais sâils ne le sont pas ? Comment atteindre un Ă©lĂ©ment arbitraire de la page ?
Il existe dâautres mĂ©thodes de recherche pour cela.
document.getElementById ou juste id
Si un Ă©lĂ©ment a lâattribut id, on peut atteindre cet Ă©lĂ©ment en utilisant la mĂ©thode document.getElementById(id), peu importe oĂč elle se trouve.
Par exemple :
<div id="elem">
<div id="elem-content">Elément</div>
</div>
<script>
// récupération de l'élément :
let elem = document.getElementById('elem');
// on met son arriĂšre-plan rouge :
elem.style.background = 'red';
</script>
Il y a aussi une variable globale nommĂ©e selon lâid qui rĂ©fĂ©rence lâĂ©lĂ©ment :
<div id="elem">
<div id="elem-content">Elément</div>
</div>
<script>
// elem est une référence à l'élément du DOM ayant l'id "elem"
elem.style.background = 'red';
// id="elem-content" contient un tiret, donc ça ne peut pas ĂȘtre un nom de variable
// ...mais on peut y accéder en utilisant les crochets : window['elem-content']
</script>
âŠA moins quâon dĂ©clare une variable JavaScript avec le mĂȘme nom, auquel cas celle-ci obtient la prioritĂ© :
<div id="elem"></div>
<script>
let elem = 5; // maintenant elem vaut 5, ce n'est plus une référence à <div id="elem">
alert(elem); // 5
</script>
Ce comportement est décrit dans la spécification, mais il est pris en charge principalement pour la compatibilité .
Le navigateur essaie de nous aider en mĂ©langeant les noms de JS et du DOM. Câest bien pour des scripts simples, intĂ©grĂ© dans du HTML, mais en gĂ©nĂ©ral ce nâest pas bon. Il peut y avoir des conflits de noms. Aussi, quand quelquâun lira le code JS sans avoir le HTML Ă cĂŽtĂ©, ce ne sera pas Ă©vident pour lui dâoĂč vient la variable.
Dans ce tutoriel, on utilise id pour directement rĂ©fĂ©rencer un Ă©lĂ©ment rapidement, quand il sera Ă©vident dâoĂč il vient.
Dans la vraie vie, document.getElementById est la méthode à avantager.
id doit ĂȘtre uniqueLâid doit ĂȘtre unique. Il ne peut y avoir quâun Ă©lĂ©ment dans le document avec un id donnĂ©.
Sâil y a de multiples Ă©lĂ©ments avec le mĂȘme id, alors le comportement de la mĂ©thode qui lâutilise est imprĂ©visible, par exemple document.getElementById pourra renvoyer nâimporte lequel de ces Ă©lĂ©ments alĂ©atoirement. Donc suivez la rĂšgle et gardez lâid unique.
document.getElementById, pas anyElem.getElementByIdLa mĂ©thode getElementById ne peut ĂȘtre appelĂ©e que sur lâobjet document . Elle va chercher lâid dans le document entier.
querySelectorAll
De loin, la mĂ©thode la plus polyvalente, elem.querySelectorAll(css) renvoie tous les Ă©lĂ©ments Ă lâintĂ©rieur de elem correspondant au sĂ©lecteur CSS donnĂ© en paramĂštre
Ici, on recherche tous les éléments <li> qui sont les derniers enfants :
<ul>
<li>Le</li>
<li>test</li>
</ul>
<ul>
<li>a</li>
<li>réussi</li>
</ul>
<script>
let elements = document.querySelectorAll('ul > li:last-child');
for (let elem of elements) {
alert(elem.innerHTML); // "test", "réussi"
}
</script>
Cette mĂ©thode est trĂšs puissante, car tous les sĂ©lecteurs CSS peuvent ĂȘtre utilisĂ©s.
Les pseudo-classes dans le sĂ©lecteur CSS comme :hover et :active sont aussi acceptĂ©s. Par exemple, document.querySelectorAll(':hover') renverra lâensemble des Ă©lĂ©ments dont le curseur est au-dessus en ce moment (dans lâordre dâimbrication : du plus extĂ©rieur <html> au plus imbriquĂ©).
querySelector
Un appel Ă elem.querySelector(css) renverra le premier Ă©lĂ©ment dâun sĂ©lecteur CSS donnĂ©.
En dâautres termes, le rĂ©sultat sera le mĂȘme que elem.querySelectorAll(css)[0], mais celui-ci cherchera tous les Ă©lĂ©ments et en choisira un seul, alors que elem.querySelector nâen cherchera quâun. Câest donc plus rapide, et plus court Ă Ă©crire.
matches
Les méthodes précédentes recherchaient dans le DOM.
La commande elem.matches(css) ne recherche rien, elle vérifie simplement que elem correspond au sélecteur CSS donné. Elle renvoie true ou false.
Cette mĂ©thode devient utile quand on itĂšre sur des Ă©lĂ©ments (comme dans un array par exemple) et quâon veut filtrer ceux qui nous intĂ©ressent.
Par exemple :
<a href="http://example.com/file.zip">...</a>
<a href="http://ya.ru">...</a>
<script>
// on peut mettre n'importe quel ensemble Ă la place de document.body.children
for (let elem of document.body.children) {
if (elem.matches('a[href$="zip"]')) {
alert("le lien de l'archive : " + elem.href );
}
}
</script>
closest
Les ancĂȘtres dâun Ă©lĂ©ment sont : le parent, le parent du parent, son propre parent etc⊠Les ancĂȘtres forment une chaĂźne de parents depuis lâĂ©lĂ©ment jusquâau sommet.
La mĂ©thode elem.closest(css) cherche lâancĂȘtre le plus proche qui correspond au sĂ©lecteur CSS. LâĂ©lĂ©ment elem est lui-mĂȘme inclus dans la recherche.
En dâautres mots, la mĂ©thode closest part de lâĂ©lĂ©ment et remonte en regardant chacun des parents. Sâil correspond au sĂ©lecteur, la recherche sâarrĂȘte et lâancĂȘtre est renvoyĂ©.
Par exemple :
<h1>Contenu</h1>
<div class="contents">
<ul class="book">
<li class="chapter">ChapĂźtre 1</li>
<li class="chapter">ChapĂźtre 2</li>
</ul>
</div>
<script>
let chapter = document.querySelector('.chapter'); // LI
alert(chapter.closest('.book')); // UL
alert(chapter.closest('.contents')); // DIV
alert(chapter.closest('h1')); // null (car h1 n'est pas un ancĂȘtre)
</script>
getElementsBy*
Il y a aussi dâautres mĂ©thodes pour rechercher des balises par tag, classe, etcâŠ
Aujourdâhui, elles sont principalement de lâhistoire ancienne, car querySelector est plus puissante et plus courte Ă Ă©crire.
Donc ici, on va surtout en parler dans le souci dâĂȘtre complet, comme elles peuvent encore se retrouver dans des vieux scripts.
elem.getElementsByTagName(tag)cherche les Ă©lĂ©ments avec le tag donnĂ© et renvoie lâensemble de ces Ă©lĂ©ments. Le paramĂštretagpeut aussi ĂȘtre une Ă©toile"*"pour signifier nâimporte quel tag.elem.getElementsByClassName(className)renvoie les Ă©lĂ©ments qui ont la classe CSS donnĂ©e.document.getElementsByName(name)renvoie les Ă©lĂ©ments qui ont lâattributname, dans tout le document. TrĂšs rarement utilisĂ©.
Par exemple:
// récupérer tous les divs du document.
let divs = document.getElementsByTagName('div');
Trouvons tous les tags input dans le tableau :
<table id="table">
<tr>
<td>Votre Ăąge:</td>
<td>
<label>
<input type="radio" name="age" value="young" checked> moins de 18
</label>
<label>
<input type="radio" name="age" value="mature"> entre 18 et 50
</label>
<label>
<input type="radio" name="age" value="senior"> plus de 60
</label>
</td>
</tr>
</table>
<script>
let inputs = table.getElementsByTagName('input');
for (let input of inputs) {
alert( input.value + ': ' + input.checked );
}
</script>
"s" !Les dĂ©veloppeurs junior oublient parfois la lettre "s". Ils essaient donc dâappeler getElementByTagName au lieu de getElementsByTagName.
La lettre "s" letter nâapparaĂźt pas dans getElementById, car cette mĂ©thode renvoie un seul Ă©lĂ©ment. Mais getElementsByTagName renvoie un ensemble dâĂ©lĂ©ments, il y a donc un "s".
Une autre erreur rĂ©pandue parmi les dĂ©butants est dâĂ©crire :
// ne fonctionne pas :
document.getElementsByTagName('input').value = 5;
Cela ne va pas marcher, parce quâon essaie dâaffecter une valeur Ă un ensemble dâobjets plutĂŽt quâĂ un Ă©lĂ©ment de cet ensemble. On devrait plutĂŽt itĂ©rer sur lâensemble ou rĂ©cupĂ©rer un Ă©lĂ©ment par son index, et lui affecter la valeur, comme ceci :
// doit fonctionner (s'il y a un élément 'input' )
document.getElementsByTagName('input')[0].value = 5;
Recherche des éléments .article :
<form name="my-form">
<div class="article">Article</div>
<div class="long article">Long article</div>
</form>
<script>
// recherche par attribut nom
let form = document.getElementsByName('my-form')[0];
// recherche par classe dans le formulaire
let articles = form.getElementsByClassName('article');
alert(articles.length); // 2 éléments trouvés avec la classe 'article'
</script>
Ensembles courants
Toutes les mĂ©thodes "getElementsBy*" renvoient lâensemble courant. De tels ensembles montrent toujours lâĂ©tat courant du document et se mettent Ă jour automatiquement quand celui-ci change.
Dans lâexemple ci-dessous, il y a deux scripts :
- Le premier crĂ©e une rĂ©fĂ©rence Ă lâensemble des
<div>. Maintenant, sa longueur est1. - Le second se lance aprÚs que le navigateur aie rencontré un autre
<div>, donc sa longueur est2.
<div>Premier div</div>
<script>
let divs = document.getElementsByTagName('div');
alert(divs.length); // 1
</script>
<div>Second div</div>
<script>
alert(divs.length); // 2
</script>
A lâopposĂ©, querySelectorAll renvoie un ensemble statique. Câest comme un tableau fixe dâĂ©lĂ©ments
Si on lâutilise, alors les deux scripts ci-dessus renvoient 1:
<div>Premier div</div>
<script>
let divs = document.querySelectorAll('div');
alert(divs.length); // 1
</script>
<div>Second div</div>
<script>
alert(divs.length); // 1
</script>
Maintenant, on voit facilement la diffĂ©rence. Lâensemble statique ne sâest pas incrĂ©mentĂ© aprĂšs lâapparition dâun nouveau div dans le document.
Résumé
Il y a 6 principales méthodes pour rechercher des balises dans le DOM :
| Méthode | Recherches par... | Peut appeler un élément ? | Courant ? |
querySelector |
sĂ©lecteur CSS | â | - |
querySelectorAll |
sĂ©lecteur CSS | â | - |
getElementById |
id |
- | - |
getElementsByName |
nom |
- | â |
getElementsByTagName |
tag ou '*' |
â | â |
getElementsByClassName |
classe | â | â |
De loin, les plus utilisĂ©es sont querySelector et querySelectorAll, mais getElement(s)By* peut ĂȘtre de temps en temps utile ou rencontrĂ©e dans de vieux scripts.
A part ça :
- Il y a
elem.matches(css)qui vérifie sielemcorrespond au sélecteur CSS donné. - Il y a
elem.closest(css)qui va chercher lâancĂȘtre le plus proche qui correspond au sĂ©lecteur CSS donnĂ©.
Et on peut mentionner ici une autre méthode pour vérifier la relation parent-enfant, ce qui est parfois utile :
elemA.contains(elemB)renvoie true sielemBest danselemA(un descendant deelemA) ou quandelemA==elemB.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâŠ)