Comment puis-je trouver l'ancêtre d'un élément le plus proche de l'arbre ayant une classe particulière, en JavaScript pur? Par exemple, dans un arbre comme celui-ci:
<div class="far ancestor">
<div class="near ancestor">
<p>Where am I?</p>
</div>
</div>
Ensuite, je veux div.near.ancestor
si je l’essaye sur p
et que je cherche ancestor
.
Mise à jour: Maintenant supporté dans la plupart des navigateurs principaux
document.querySelector("p").closest(".near.ancestor")
Notez que cela peut correspondre aux sélecteurs, pas seulement aux classes
https://developer.mozilla.org/en-US/docs/Web/API/Element.closest
Pour les anciens navigateurs qui ne prennent pas en charge closest()
mais qui ont matches()
, vous pouvez créer une correspondance de sélecteur similaire à celle de @ rvighne:
function findAncestor (el, sel) {
while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
return el;
}
Cela fait le tour:
function findAncestor (el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
La boucle while attend que el
ait la classe désirée et règle el
sur le parent de el
à chaque itération. Vous avez donc l'ancêtre avec cette classe ou null
.
Voici un violon , si quelqu'un veut l'améliorer. Cela ne fonctionnera pas sur les anciens navigateurs (IE); voir ceci tableau de compatibilité pour classList . parentElement
est utilisé ici parce que parentNode
impliquerait davantage de travail pour s'assurer que le nœud est un élément.
Utilisez element.closest ()
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
Voir cet exemple DOM:
<article>
<div id="div-01">Here is div-01
<div id="div-02">Here is div-02
<div id="div-03">Here is div-03</div>
</div>
</div>
</article>
Voici comment utiliser element.closest:
var el = document.getElementById('div-03');
var r1 = el.closest("#div-02");
// returns the element with the id=div-02
var r2 = el.closest("div div");
// returns the closest ancestor which is a div in div, here is div-03 itself
var r3 = el.closest("article > div");
// returns the closest ancestor which is a div and has a parent article, here is div-01
var r4 = el.closest(":not(div)");
// returns the closest ancestor which is not a div, here is the outmost article
Basé sur le the8472 answer et https://developer.mozilla.org/en-US/docs/Web/API/Element/matches voici la solution 2017 multiplate-forme :
if (!Element.prototype.matches) {
Element.prototype.matches =
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector ||
function(s) {
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
i = matches.length;
while (--i >= 0 && matches.item(i) !== this) {}
return i > -1;
};
}
function findAncestor(el, sel) {
if (typeof el.closest === 'function') {
return el.closest(sel) || null;
}
while (el) {
if (el.matches(sel)) {
return el;
}
el = el.parentElement;
}
return null;
}
La solution @rvighne fonctionne bien, mais comme indiqué dans les commentaires, ParentElement
et ClassList
présentent tous deux des problèmes de compatibilité. Pour le rendre plus compatible, j'ai utilisé:
function findAncestor (el, cls) {
while ((el = el.parentNode) && el.className.indexOf(cls) < 0);
return el;
}
parentNode
à la place de la propriété parentElement
indexOf
sur la propriété className
à la place de la méthode contains
sur la propriété classList
.Bien sûr, indexOf recherche simplement la présence de cette chaîne, peu importe si c'est la chaîne entière ou non. Donc, si vous avez un autre élément avec la classe 'ancêtre-type', il retournera toujours comme ayant trouvé 'ancêtre'. Si cela vous pose problème, vous pouvez peut-être utiliser regexp pour trouver une correspondance exacte.