Zoek het dichtstbijzijnde voorouderelement dat een specifieke klasse heeft

Hoe kan ik de voorouder van een element vinden die zich het dichtst bij de boom met een bepaalde klasse bevindt, in puur JavaScript? Bijvoorbeeld in een boom als volgt:

<div class="far ancestor">
    <div class="near ancestor">
        <p>Where am I?</p>
    </div>
</div>

Dan wil ik div.near.ancestorals ik dit probeer op de pen zoek naar ancestor.


Antwoord 1, autoriteit 100%

Update: nu ondersteund in de meeste grote browsers

document.querySelector("p").closest(".near.ancestor")

Merk op dat dit kan overeenkomen met selectors, niet alleen klassen

https://developer.mozilla.org/en- VS/docs/Web/API/Element.closest


Voor oudere browsers die closest()niet ondersteunen maar wel matches()hebben, kan men selector-matching bouwen die lijkt op de class matching van @rvighne:

function findAncestor (el, sel) {
    while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
    return el;
}

Antwoord 2, autoriteit 43%

Dit doet de truc:

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

De while-lus wacht totdat elde gewenste klasse heeft, en zet elbij elke iteratie op de ouder van el, dus uiteindelijk , je hebt de voorouder met die klasse of null.

Hier is een viool, als iemand het wil verbeteren. Het werkt niet in oude browsers (d.w.z. IE); zie deze compatibiliteitstabel voor classList. parentElementwordt hier gebruikt omdat parentNodemeer werk zou vergen om ervoor te zorgen dat de node een element is.


Antwoord 3, autoriteit 11%

Gebruik element.closest()

https://developer.mozilla.org/en- VS/docs/Web/API/Element/dichtstbijzijnde

Zie dit voorbeeld 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>

Zo zou je element.closest gebruiken:

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

Antwoord 4, autoriteit 4%

Op basis van het de8472-antwoorden https://developer.mozilla.org/en-US/docs/Web/API/Element/matcheshier is cross-platform 2017 oplossing:

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

Other episodes