Javascript closest

Javascript closest()

closest() gibt das nahegelegenste Elternelement zurück, das einem Selektor entspricht, oder eine Referenz auf sich selber, wenn das Element selbst schon zum Selektor passt. Das erspart viele Abfragen und macht den Scriptcode lesbarer.

Das ist genauso komfortabel wie die gleichnamige jQuery-Methode und wird von allen modernen Browsern (außer von IE11) unterstützt.

closest – die Suche nach dem Vorfahren

Die Suche nach dem Urvater gehört vor allem in Slideshows und verschachtelten Menüs zu den häufigsten Aufgaben.

closest() findet das nächste übergeordnete Element – einen Vorfahren – anhand eines einfachen Selektors. closest() gehört zu den eleganten jQuery-Methoden, die wir im reinen Javascript schmerzlich vermisst haben.

Inzwischen gehört closest() zu den DOM-Methoden von Vanilla Javascript, und wird auch schon auf den älteren Versionen der mobilen Geräte (iOS ab Version 9, Android 76 ) unterstützt, nicht aber von IE11.

closest-3
Giftkesselchen
closest-3
Seitenwagen
closest-3
Tulpen
const caption = document.querySelectorAll(".block-column figcaption");
for (let i=0; i<3; i++) {
   caption[i].addEventListener ("click", function () {
      this.closest("figure").firstElementChild.setAttribute("src","img/closest-" + (i+1) + ".jpg");
   });
}

Die herkömmlichen Methoden parentNode oder parentElement erwischt nur den direkten Vorfahren und müssen in einer Schleife bei jedem Vorfahren fragen, ob er dem gewünschten Selektor entspricht. Dabei muss zusätzlich geprüft werden, ob das aktuelle Element das document-Element ist. Dann wäre das Dokument vollständig durchsucht und parentNode / parentElement hätte keinen Treffer gelandet.

Um IE11 mit closest() bekannt zu machen, behilft man sich mit einem Polyfill.

if (window.Element && !Element.prototype.closest) {
    Element.prototype.closest =
    function(s) {
        var matches = (this.document || this.ownerDocument).querySelectorAll(s),
            i,
            el = this;
        do {
            i = matches.length;
            while (--i >= 0 && matches.item(i) !== el) {};
        } while ((i < 0) && (el = el.parentElement));
        return el;
    };
}

matches()

Passt gut zu closest: matches(). matches() stellt fest, ob ein Element zum einem bestimmten Selektor passt. matches wird von allen modernen Browsern unterstützt, nur IE11 braucht noch einen Präfix.

if (elem.matches(selector))

Ein find() als Pendant zu closest() – so wie in jQuery – gibt es übrigens nicht, und obendrein ist find() schon von array besetzt.

parentElement

querySelectorAll, getElementsByTagName und getElementsByClassName geben NodeLists (auch Collections oder Sammlungen) zurück – das sind keine Arrays. Für die Bestimmung des Index in einer NodeList wird parentNode oder parentElement gebraucht:

  • Ananas
  • Erdbeere
  • Melone
<ul class="fruity">
  <li>Ananas</li>
  <li>Erdbeere</li>
  <li>Melone</li>
</ul>
// Index in einer Nodelist mit parentNode oder parentElement finden
var images = ["fruity-01.svg","fruity-02.svg","fruity-03.svg",];

var fruity = document.querySelectorAll(".fruity li");

for (var i=0; i<fruity.length; i++) {
  fruity[i].addEventListener ('click', function () {
    var img = document.createElement("IMG");
    var index = Array.prototype.indexOf.call(this.parentElement.children, this);
    img.setAttribute("src",images[index]);
    document.querySelector(".demonodes").appendChild(img);
  });
}

Anstelle von parentElement hätte parentNode denselben Zweck erfüllt, denn es ist so gut wie ausgeschlossen, dass ein Text, ein Zeilenumbruch oder ein Kommentar ein parentNode ist.