386 Stimmen

Suche nach dem nächstgelegenen Vorgängerelement, das eine bestimmte Klasse hat.

Wie kann ich in reinem JavaScript das übergeordnete Element eines Elements finden, das am nächsten am Baum liegt und eine bestimmte Klasse hat? Zum Beispiel in einem Baum wie diesem:

        Wo bin ich?

Dann möchte ich div.near.ancestor erhalten, wenn ich das auf dem p versuche und nach ancestor suche.

614voto

the8472 Punkte 37966

Aktualisierung: Jetzt unterstützt in den meisten gängigen Browsern

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

Beachten Sie, dass dies auch Selektoren übereinstimmt, nicht nur Klassen

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


Für ältere Browser, die closest() nicht unterstützen, aber matches() haben, kann man eine ähnliche Selektorübereinstimmung wie bei @rvighne's Klassenübereinstimmung erstellen:

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

209voto

rvighne Punkte 18897

Das erledigt den Trick:

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

Die While-Schleife wartet, bis el die gewünschte Klasse hat, und setzt el in jeder Iteration auf das Elternelement, sodass Sie am Ende den Vorfahren mit dieser Klasse oder null haben.

Hier ist ein Fiddle, falls jemand es verbessern möchte. Es funktioniert nicht in alten Browsern (z.B. IE); siehe diese Kompatibilitätstabelle für classList. parentElement wird hier verwendet, weil parentNode mehr Arbeit erfordern würde, um sicherzustellen, dass der Knoten ein Element ist.

78voto

simbro Punkte 3034

Verwenden Sie element.closest()

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

Siehe dieses Beispiel-DOM:

  Hier ist div-01
    Hier ist div-02
      Hier ist div-03

So verwenden Sie element.closest:

var el = document.getElementById('div-03');

var r1 = el.closest("#div-02");  
// gibt das Element mit der id=div-02 zurück

var r2 = el.closest("div div");  
// gibt den nächsten Vorfahren zurück, der ein div in div ist, hier ist div-03 selbst

var r3 = el.closest("article > div");  
// gibt den nächsten Vorfahren zurück, der ein div ist und ein Elternteilartikel hat, hier ist div-01

var r4 = el.closest(":not(div)");
// gibt den nächsten Vorfahren zurück, der kein div ist, hier ist das äußerste Artikel

18voto

marverix Punkte 6594

Basiert auf der the8472 Antwort und https://developer.mozilla.org/en-US/docs/Web/API/Element/matches ist hier die plattformübergreifende Lösung von 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;
}

15voto

Josh Punkte 376

Die Lösung von @rvighne funktioniert gut, aber wie in den Kommentaren identifiziert, haben sowohl ParentElement als auch ClassList Kompatibilitätsprobleme. Um es kompatibler zu machen, habe ich Folgendes verwendet:

function findAncestor (el, cls) {
    while ((el = el.parentNode) && el.className.indexOf(cls) < 0);
    return el;
}
  • parentNode-Eigenschaft anstelle der parentElement-Eigenschaft
  • indexOf-Methode auf der className-Eigenschaft anstelle der contains-Methode auf der classList-Eigenschaft.

Natürlich sucht indexOf einfach nach dem Vorhandensein dieses Strings, es ist ihm egal, ob es der komplette String ist oder nicht. Wenn Sie also ein anderes Element mit der Klasse 'ancestor-type' hätten, würde es immer noch als das Wort 'ancestor' gefunden werden, wenn dies ein Problem für Sie ist, können Sie vielleicht regexp verwenden, um eine genaue Übereinstimmung zu finden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X