Encuentre el elemento ancestro más cercano que tenga una clase específica

Resuelto rvighne asked hace 10 años • 6 respuestas

¿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.ancestorprobar esto py buscar ancestor.

rvighne avatar Mar 02 '14 03:03 rvighne
Aceptado

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;
}
the8472 avatar Nov 20 '2014 10:11 the8472

Esto funciona:

function findAncestor (el, cls) {
    while ((el = el.parentElement) && !el.classList.contains(cls));
    return el;
}

El bucle while espera hasta que eltenga la clase deseada y se establece elen elel 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 . parentElementse utiliza aquí porque parentNodeimplicaría más trabajo para asegurarse de que el nodo sea un elemento.

rvighne avatar Mar 01 '2014 20:03 rvighne

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
simbro avatar Mar 27 '2018 14:03 simbro

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;
}
marverix avatar Mar 18 '2017 10:03 marverix