Encuentre el elemento ancestro más cercano que tenga una clase específica
¿Cómo puedo encontrar el ancestro de un elemento que está más cerca del árbol que tiene una clase particular, en JavaScript puro ? Por ejemplo, en un árbol así:
<div class="far ancestor">
<div class="near ancestor">
<p>Where am I?</p>
</div>
</div>
Entonces quiero div.near.ancestor
probar esto p
y buscar ancestor
.
Actualización: ahora compatible con la mayoría de los principales navegadores
document.querySelector("p").closest(".near.ancestor")
Tenga en cuenta que esto puede coincidir con selectores, no solo con clases.
https://developer.mozilla.org/en-US/docs/Web/API/Element.closest
Para los navegadores heredados que no son compatibles closest()
pero que sí lo tienen, matches()
se puede crear una coincidencia de selectores similar a la coincidencia de clases de @rvighne:
function findAncestor (el, sel) {
while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
return el;
}
Esto funciona:
function findAncestor (el, cls) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el;
}
El bucle while espera hasta que el
tenga la clase deseada y se establece el
en el
el padre de cada iteración para que, al final, tenga el antepasado con esa clase o null
.
Aquí hay un violín , si alguien quiere mejorarlo. No funcionará en navegadores antiguos (es decir, IE); consulte esta tabla de compatibilidad para classList . parentElement
se utiliza aquí porque parentNode
implicaría más trabajo para asegurarse de que el nodo sea un elemento.
Utilice elemento.más cercano()
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
Vea este ejemplo de 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>
Así es como usarías 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
Basado en la respuesta the8472 y https://developer.mozilla.org/en-US/docs/Web/API/Element/matches aquí hay una solución multiplataforma 2017:
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;
}