mitmario.dev

Inhalte und Attribute lesen

JavaScript Im Browser 3 Min Lesezeit 4 BeispieleLektion 5 von 7

Ein Element gefunden zu haben heißt noch nicht, an seinen Inhalt zu kommen. Dafür gibt es je nach Frage verschiedene Wege, und die Unterschiede zwischen ihnen sind größer, als sie aussehen.

Drei Wege zum Inhalt

textContent, innerHTML und innerText
const box = document.getElementById("box");

// textContent: der reine Text aller Nachfahren, auch der
// versteckten, mit dem Leerraum aus dem Markup. JSON.stringify
// macht den Leerraum sichtbar, wie in Lektion 10.3.
console.log("textContent:", JSON.stringify(box.textContent));

// innerHTML: das Markup darin, als Text.
console.log("innerHTML:", JSON.stringify(box.innerHTML));

// innerText: was sichtbar ist. Das Versteckte fehlt, und
// der Leerraum ist zusammengefasst.
console.log("innerText:", JSON.stringify(box.innerText));

// Beim Lesen ist textContent die Wahl: es ist berechenbar
// und braucht kein Layout.
const betonung = document.querySelector("strong");
console.log("nur die Betonung:", betonung.textContent);

textContent liefert den reinen Text aller Nachfahren, ohne Tags. Versteckte Elemente zählen mit, und der Leerraum kommt genau so, wie er im Markup steht.

innerHTML liefert das Markup darin, als Text. Aus <strong>Betonung</strong> wird also genau diese Zeichenfolge und nicht nur das Wort.

innerText liefert das, was sichtbar ist. Versteckte Elemente fehlen, der Leerraum ist zusammengefasst, und weil der Browser dafür wissen muss, wie die Seite aussieht, muss er das Layout berechnen.

Zum Lesen nimmst du textContent. Es ist berechenbar, braucht kein Layout und liefert genau das, wonach man fragt. innerText ist die richtige Wahl nur, wenn du wirklich das Sichtbare meinst, und das ist selten.

Alle drei kannst du direkt nachfragen: tipp document.getElementById("box").textContent in die Eingabezeile der Console, danach dasselbe mit .innerHTML und mit .innerText, dann stehen die drei Antworten untereinander. Die erste bringt den Zeilenumbruch und den Einzug aus dem Markup mit, als \n geschrieben, und den versteckten Span. Die zweite dazu die Tags. Die dritte antwortet mit "Ein Satz mit Betonung darin.": kein Leerraum, kein Versteckt. Dass innerText hier antworten kann, liegt daran, dass die Seite hinter dem Reiter Console ihr Layout behält; im echten Betrieb ist genau diese Abhängigkeit vom Layout der Grund, warum es langsam ist.

innerHTML beim Lesen ist harmlos. Beim Schreiben ist es das nicht, und warum, steht in Abschnitt 11 und noch einmal in Abschnitt 20.

Attribut oder Eigenschaft

Attribut oder Eigenschaft
const link = document.getElementById("link");

// getAttribute liefert, was wörtlich im Markup steht.
console.log("Attribut:", link.getAttribute("href"));

// Die Eigenschaft liefert die aufgelöste Adresse. Wie sie
// aussieht, hängt davon ab, unter welcher Adresse die Seite
// läuft, deshalb steht sie in keiner Prüfung dieses Kurses.
console.log("Eigenschaft:", link.href);

// Bei class heißt die Eigenschaft anders als das Attribut,
// weil class in JavaScript ein reserviertes Wort ist.
console.log("Attribut class:", link.getAttribute("class"));
console.log("Eigenschaft className:", link.className);

// Und bei einem Eingabefeld laufen die beiden auseinander,
// sobald jemand tippt: das Attribut bleibt der Anfangswert,
// die Eigenschaft ist der aktuelle. Abschnitt 13 baut darauf auf.
const feld = document.getElementById("feld");
console.log("Attribut value:", feld.getAttribute("value"));
console.log("Eigenschaft value:", feld.value);

Für viele Attribute gibt es zwei Zugänge, und sie liefern nicht immer dasselbe.

getAttribute("href") liefert, was wörtlich im Markup steht. Die Eigenschaft link.href liefert die aufgelöste Adresse, also den vollständigen Pfad samt Herkunft. Wie der aussieht, hängt davon ab, unter welcher Adresse die Seite läuft, und deshalb kommt er in keiner Prüfung dieses Kurses vor.

Bei class heißen die beiden verschieden: das Attribut ist class, die Eigenschaft className. Der Grund ist historisch, class ist in JavaScript ein reserviertes Wort.

Der wichtigste Fall kommt in Abschnitt 13 wieder. Bei einem Eingabefeld ist das Attribut value der Anfangswert aus dem Markup, die Eigenschaft value der aktuelle Wert. Sobald jemand tippt, laufen die beiden auseinander, und wer das Attribut liest, bekommt immer den alten Stand.

Die Faustregel: nimm die Eigenschaft, wenn es eine gibt und du den aktuellen Zustand willst. getAttribute nimmst du für alles, was nur im Markup steht.

Eigene Daten am Element

Eigene Daten mit data-
const karte = document.querySelector(".karte");

// Alles, was mit data- beginnt, landet in dataset.
console.log("dataset:", JSON.stringify({ ...karte.dataset }));

// Aus data-kurs-id wird kursId: die Bindestriche fallen weg,
// der nächste Buchstabe wird groß.
console.log("kursId:", karte.dataset.kursId);
console.log("preisCent:", karte.dataset.preisCent);

// Es ist immer Text. Auch wenn eine Zahl darin steht.
console.log("Typ:", typeof karte.dataset.preisCent);
console.log("gerechnet:", Number(karte.dataset.preisCent) / 100);

// Und auch ein false ist nur der Text "false", also
// wahr genug im Sinn von Lektion 3.3.
console.log("als Text:", karte.dataset.frei);
console.log("richtig geprüft:", karte.dataset.frei === "true");

Wenn du eigene Angaben am Markup ablegen willst, ist data- der vorgesehene Weg. Ein data-kurs-id="js" ist gültiges HTML, stört niemanden und ist in JavaScript sofort da.

Alle diese Attribute landen in dataset. Der Name wird dabei umgeschrieben: die Bindestriche fallen weg, der nächste Buchstabe wird groß. Aus data-kurs-id wird dataset.kursId. Das ist dieselbe Umschreibung wie bei den CSS-Eigenschaften in Abschnitt 11.

Der Inhalt ist immer Text. Auch wenn eine Zahl darin steht. Zum Rechnen brauchst du also Number(...) aus Lektion 2.7, sonst verkettest du.

Und ein data-frei="false" ist der Text "false", nicht der Wahrheitswert. Ein nichtleerer Text ist wahr genug im Sinn von Lektion 3.3, also ist if (karte.dataset.frei) immer wahr. Verglichen wird deshalb ausdrücklich mit === "true".

Und die Klassen

Klassen abfragen
const karte = document.querySelector(".karte");

// classList.contains fragt nach genau einer Klasse.
console.log("hervor:", karte.classList.contains("hervor"));
console.log("klein:", karte.classList.contains("klein"));

// classList ist außerdem eine Liste.
console.log("Anzahl:", karte.classList.length);
console.log("alle:", [...karte.classList]);

// className ist dagegen der ganze Text am Stück, und
// deshalb der falsche Weg für die Frage nach einer Klasse.
console.log("className:", karte.className);
console.log("naiv geprüft:", karte.className.includes("gross"));

// Das sieht richtig aus und trifft auch bei einer Klasse
// namens grossartig. Deshalb classList.contains.

classList.contains("hervor") fragt nach genau einer Klasse und liefert true oder false. Das ist der richtige Weg.

classList ist außerdem eine Liste: sie hat length, und mit den drei Punkten machst du ein Array daraus. In Abschnitt 11 kommen add, remove und toggle dazu.

className liefert dagegen den ganzen Klassen-Text am Stück. Damit kann man arbeiten, und für die Frage nach einer Klasse ist es der falsche Weg: className.includes("gross") trifft auch bei einer Klasse namens grossartig. Das ist genau die Sorte Fehler, die erst auftritt, wenn jemand später eine Klasse dazunimmt.

Zum Mitnehmen

Zum Lesen nimmst du textContent. innerHTML gibt dir Markup als Text, und was du damit anfängst, wird in Abschnitt 20 zum Sicherheitsthema.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 4 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.