034.4 Lektion 1
Zertifikat: |
Web Development Essentials |
---|---|
Version: |
1.0 |
Thema: |
034 JavaScript Programming |
Lernziel: |
034.4 JavaScript-Manipulation von Website-Inhalt und -Gestaltung |
Lektion: |
1 von 1 |
Einführung
HTML, CSS und JavaScript sind drei verschiedene Technologien, die im Web zusammenspielen. Um wirklich dynamische und interaktive Seiten zu erstellen, müssen JavaScript-Programmierer Komponenten aus HTML und CSS zur Laufzeit kombinieren; diese Aufgabe erleichtert das Document Object Model (DOM) erheblich.
Interaktion mit dem DOM
Das DOM ist eine Datenstruktur, die als Programmierschnittstelle zum Dokument fungiert, wobei jeder Aspekt des Dokuments als Knoten im DOM dargestellt wird und jede am DOM vorgenommene Änderung sich sofort im Dokument niederschlägt. Um zu sehen, wie das DOM in JavaScript verwendet werden kann, speichern Sie den folgenden HTML-Code in einer Datei mit dem Namen example.html
:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>HTML Manipulation with JavaScript</title>
</head>
<body>
<div class="content" id="content_first">
<p>The dynamic content goes here</p>
</div><!-- #content_first -->
<div class="content" id="content_second" hidden>
<p>Second section</p>
</div><!-- #content_second -->
</body>
</html>
Das DOM steht erst zur Verfügung, wenn der HTML-Code geladen ist. Schreiben Sie daher das folgende JavaScript am Ende des Seitenkörpers (vor dem abschließenden </body>
-Tag):
<script>
let body = document.getElementsByTagName("body")[0];
console.log(body.innerHTML);
</script>
Das Objekt document
ist das oberste DOM-Element, von dem alle anderen Elemente abzweigen. Die Methode getElementsByTagName()
listet alle Elemente auf, die von document
abstammen und den angegebenen Tag-Namen haben. Obwohl das Tag body
nur einmal im Dokument verwendet wird, gibt die Methode getElementsByTagName()
immer eine Array-ähnliche Sammlung der gefundenen Elemente zurück — daher die Verwendung des Index [0]
, um das erste (und einzige) gefundene Element zurückzugeben.
HTML-Inhalt
Wie im vorangegangenen Beispiel gezeigt, wurde das DOM-Element, das von document.getElementsByTagName("body")[0]
zurückgegeben wurde, der Variablen body
zugewiesen. Die Variable body
kann dann verwendet werden, um das Body-Element der Seite zu manipulieren, da es alle DOM-Methoden und Attribute von diesem Element erbt. Zum Beispiel enthält die Eigenschaft innerHTML
den gesamten HTML-Auszeichnungscode, der innerhalb des entsprechenden Elements geschrieben wurde, so dass sie zum Lesen der inneren Auszeichnung verwendet werden kann. Unser Aufruf console.log(body.innerHTML)
gibt den Inhalt innerhalb von <body></body>
auf der Webkonsole aus. Die Variable kann auch verwendet werden, um diesen Inhalt zu ersetzen, wie in body.innerHTML = "<p>Content erased</p>"
.
Anstatt ganze Teile des HTML-Markups zu ändern, ist es praktischer, die Dokumentstruktur unverändert zu lassen und nur mit den Elementen zu interagieren. Sobald das Dokument vom Browser gerendert wird, sind alle Elemente über DOM-Methoden zugänglich. Es ist zum Beispiel möglich, alle HTML-Elemente aufzulisten und darauf zuzugreifen, indem man das spezielle Zeichen *
in der Methode getElementsByTagName()
des document
-Objekts verwendet:
let elements = document.getElementsByTagName("*");
for ( element of elements )
{
if ( element.id == "content_first" )
{
element.innerHTML = "<p>New content</p>";
}
}
Dieser Code speichert alle in document
gefundenen Elemente in der Variablen elements
. Die Variable elements
ist ein Array-ähnliches Objekt, so dass wir mit einer for
-Schleife über alle Elemente iterieren können. Wenn die HTML-Seite, auf der dieser Code ausgeführt wird, ein Element hat, dessen id
-Attribut auf content_first
gesetzt ist (siehe die zu Beginn der Lektion gezeigte HTML-Beispielseite), trifft die if
-Anweisung auf dieses Element zu und sein Markup-Inhalt wird in <p>New content</p>
geändert. Beachten Sie, dass die Attribute eines HTML-Elements im DOM über die dot-Notation der JavaScript-Objekteigenschaften zugänglich sind: Daher bezieht sich element.id
auf das Attribut id
des aktuellen Elements der for
-Schleife. Die Methode getAttribute()
könnte auch verwendet werden, wie in element.getAttribute("id")
.
Es ist nicht notwendig, alle Elemente zu durchlaufen, wenn Sie nur einige untersuchen wollen. Die Methode document.getElementsByClassName()
schränkt beispielsweise die übereinstimmenden Elemente auf diejenigen ein, die eine bestimmte Klasse haben:
let elements = document.getElementsByClassName("content");
for ( element of elements )
{
if ( element.id == "content_first" )
{
element.innerHTML = "<p>New content</p>";
}
}
Die Iteration über viele Dokumentelemente mit Hilfe einer Schleife ist jedoch nicht die beste Strategie, wenn Sie ein bestimmtes Element auf der Seite ändern müssen.
Bestimmte Elemente auswählen
JavaScript bietet optimierte Methoden, um genau das Element auszuwählen, an dem Sie arbeiten wollen. Sie könnten die vorherige Schleife vollständig durch die Methode document.getElementById()
ersetzen:
let element = document.getElementById("content_first");
element.innerHTML = "<p>New content</p>";
Jedes id
-Attribut im Dokument muss eindeutig sein, daher gibt die Methode document.getElementById()
nur ein einziges DOM-Objekt zurück. Sogar die Deklaration der Variable element
kann weggelassen werden, weil JavaScript uns erlaubt, Methoden direkt zu verketten:
document.getElementById("content_first").innerHTML = "<p>New content</p>";
Die Methode getElementById()
ist der bevorzugte Weg, um Elemente im DOM zu finden, da sie bei komplexen Dokumenten deutlich performanter ist als iterative Methoden. Allerdings haben nicht alle Elemente eine explizite ID, und die Methode gibt einen null Wert zurück, wenn kein Element mit der angegebenen ID übereinstimmt (dies verhindert auch die Verwendung verketteter Attribute oder Funktionen, wie der im obigen Beispiel verwendeten innerHTML
). Außerdem ist es praktischer, ID-Attribute nur den Hauptkomponenten der Seite zuzuweisen und dann CSS-Selektoren zu verwenden, um ihre untergeordneten Elemente zu finden.
Selektoren, die in einer früheren Lektion zu CSS vorgestellt wurden, sind Muster, die auf Elemente im DOM passen. Die Methode querySelector()
gibt das erste übereinstimmende Element im DOM-Baum zurück, während querySelectorAll()
alle Elemente zurückgibt, die dem angegebenen Selektor entsprechen.
Im vorherigen Beispiel ruft die Methode getElementById()
das Element mit der ID content_first
ab. Die Methode querySelector()
erfüllt dieselbe Aufgabe:
document.querySelector("#content_first").innerHTML = "<p>New content</p>";
Da die Methode querySelector()
die Selektor-Syntax verwendet, muss die angegebene ID mit einem Rautezeichen beginnen. Wird kein passendes Element gefunden, gibt die Methode querySelector()
null zurück.
Im vorigen Beispiel wird der gesamte Inhalt des Div content_first
durch die angegebene Textzeichenfolge ersetzt. Die Zeichenfolge enthält HTML-Code, was nicht als best practice gilt. Sie müssen vorsichtig sein, wenn Sie hart kodierten HTML-Code zu JavaScript-Code hinzufügen, da die Verfolgung von Elementen schwierig werden kann, wenn Änderungen an der gesamten Dokumentstruktur erforderlich sind.
Selektoren sind nicht auf die ID des Elements beschränkt. Das interne Element p
kann direkt angesprochen werden:
document.querySelector("#content_first p").innerHTML = "New content";
Der Selektor #content_first p
passt nur auf das erste p
-Element innerhalb des #content_first
-Div. Das funktioniert gut, wenn wir das erste Element bearbeiten wollen. Vielleicht wollen wir aber den zweiten Absatz ändern:
<div class="content" id="content_first">
<p>Don't change this paragraph.</p>
<p>The dynamic content goes here.</p>
</div><!-- #content_first -->
In diesem Fall nutzen wir die Pseudoklasse :nth-child(2)
, um das zweite p
-Element zu finden:
document.querySelector("#content_first p:nth-child(2)").innerHTML = "New content";
Die Zahl 2
in p:nth-child(2)
bezeichnet den zweiten Absatz, der dem Selektor entspricht. In der Lektion über CSS-Selektoren erfahren Sie mehr über Selektoren und ihre Verwendung.
Mit Attributen arbeiten
Die Fähigkeit von JavaScript, mit dem DOM zu interagieren, ist nicht auf die Manipulation von Inhalten beschränkt. Die häufigste Verwendung von JavaScript im Browser besteht tatsächlich darin, die Attribute der vorhandenen HTML-Elemente zu ändern.
Nehmen wir an, unsere ursprüngliche HTML-Beispielseite hat jetzt drei Inhaltsabschnitte:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>HTML Manipulation with JavaScript</title>
</head>
<body>
<div class="content" id="content_first" hidden>
<p>First section.</p>
</div><!-- #content_first -->
<div class="content" id="content_second" hidden>
<p>Second section.</p>
</div><!-- #content_second -->
<div class="content" id="content_third" hidden>
<p>Third section.</p>
</div><!-- #content_third -->
</body>
</html>
Möglicherweise möchten Sie jeweils nur eines von ihnen sichtbar machen, daher das Attribut hidden
in allen div
-Tags. Dies ist z.B. nützlich, um nur ein Bild aus einer Bildergalerie anzuzeigen. Um eines der Bilder beim Laden der Seite sichtbar zu machen, fügen Sie den folgenden JavaScript-Code in die Seite ein:
// Which content to show
let content_visible;
switch ( Math.floor(Math.random() * 3) )
{
case 0:
content_visible = "#content_first";
break;
case 1:
content_visible = "#content_second";
break;
case 2:
content_visible = "#content_third";
break;
}
document.querySelector(content_visible).removeAttribute("hidden");
Der von der Anweisung switch
ausgewertete Ausdruck gibt zufällig die Zahl 0, 1 oder 2 zurück. Der entsprechende ID-Selektor wird dann der Variablen content_visible
zugewiesen, die von der Methode querySelector(content_visible)
verwendet wird. Der verkettete Aufruf removeAttribute("hidden")
entfernt das Attribut hidden
aus dem Element.
Der umgekehrte Ansatz ist ebenfalls möglich: Alle Abschnitte könnten zunächst sichtbar sein (ohne das Attribut hidden
), und das JavaScript-Programm kann dann jedem Abschnitt außer dem in content_visible
das Attribut hidden
zuweisen. Dafür müssen Sie alle Inhalts-Div-Elemente durchgehen, die sich von dem ausgewählten unterscheiden, was mit der Methode querySelectorAll()
geschieht:
// Which content to show
let content_visible;
switch ( Math.floor(Math.random() * 3) )
{
case 0:
content_visible = "#content_first";
break;
case 1:
content_visible = "#content_second";
break;
case 2:
content_visible = "#content_third";
break;
}
// Hide all content divs, except content_visible
for ( element of document.querySelectorAll(".content:not("+content_visible+")") )
{
// Hidden is a boolean attribute, so any value will enable it
element.setAttribute("hidden", "");
}
Wenn die Variable content_visible
auf #content_first
gesetzt wurde, lautet der Selektor .content:not(#content_first)
, was bedeutet, dass alle Elemente mit der Klasse content
außer denen mit der ID content_first
angezeigt werden. Die Methode setAttribute()
fügt Attribute von HTML-Elementen hinzu oder ändert sie. Ihr erster Parameter ist der Name des Attributs und der zweite der Wert des Attributs.
Der richtige Weg, um das Erscheinungsbild von Elementen zu ändern, führt jedoch über CSS. In diesem Fall können wir die CSS-Eigenschaft display
auf hidden
setzen und sie dann mit JavaScript in block
ändern:
<style>
div.content { display: none }
</style>
<div class="content" id="content_first">
<p>First section.</p>
</div><!-- #content_first -->
<div class="content" id="content_second">
<p>Second section.</p>
</div><!-- #content_second -->
<div class="content" id="content_third">
<p>Third section.</p>
</div><!-- #content_third -->
<script>
// Which content to show
let content_visible;
switch ( Math.floor(Math.random() * 3) )
{
case 0:
content_visible = "#content_first";
break;
case 1:
content_visible = "#content_second";
break;
case 2:
content_visible = "#content_third";
break;
}
document.querySelector(content_visible).style.display = "block";
</script>
Dieselben Verfahren für das Mischen von HTML-Tags mit JavaScript gelten auch für CSS. So ist es nicht empfehlenswert, CSS-Eigenschaften direkt in JavaScript-Code zu schreiben. Stattdessen sollten Sie CSS-Regeln getrennt vom JavaScript-Code schreiben. Der richtige Weg zur alternativen visuellen Gestaltung besteht darin, eine vordefinierte CSS-Klasse für das Element auszuwählen.
Mit Klassen arbeiten
Elemente können mehr als eine zugehörige Klasse haben, was es einfacher macht, Stile zu schreiben, die bei Bedarf hinzugefügt oder entfernt werden. Es wäre mühsam, viele CSS-Attribute direkt in JavaScript zu ändern. Daher können Sie eine neue CSS-Klasse mit diesen Attributen erstellen und die Klasse dann dem Element hinzufügen. DOM-Elemente haben die Eigenschaft classList
, mit der die dem entsprechenden Element zugewiesenen Klassen angezeigt und bearbeitet werden.
Anstatt die Sichtbarkeit des Elements zu ändern, können wir zum Beispiel eine zusätzliche CSS-Klasse erstellen, um unser content
-Div hervorzuheben:
div.content {
border: 1px solid black;
opacity: 0.25;
}
div.content.highlight {
border: 1px solid red;
opacity: 1;
}
Dieses Stylesheet fügt allen Elementen mit der Klasse content
einen dünnen schwarzen Rand und Semitransparenz hinzu. Nur die Elemente, die auch die Klasse highlight
haben, werden vollständig undurchsichtig sein und den dünnen roten Rand haben. Anstatt die CSS-Eigenschaften direkt zu ändern, wie wir es zuvor unternommen haben, können wir die Methode classList.add("highlight")
in dem ausgewählten Element verwenden:
// Which content to highlight
let content_highlight;
switch ( Math.floor(Math.random() * 3) )
{
case 0:
content_highlight = "#content_first";
break;
case 1:
content_highlight = "#content_second";
break;
case 2:
content_highlight = "#content_third";
break;
}
// Highlight the selected div
document.querySelector(content_highlight).classList.add("highlight");
Alle Techniken und Beispiele, die wir bisher kennengelernt haben, wurden am Ende des Ladevorgangs der Seite ausgeführt, aber sie sind nicht auf diese Phase beschränkt. Was JavaScript für Webentwickler so nützlich macht, ist seine Fähigkeit, auf Ereignisse auf der Seite zu reagieren, wie wir im Folgenden sehen werden.
Event Handler
Alle sichtbaren Seitenelemente sind empfänglich für interaktive Ereignisse, wie z.B. den Klick oder die Bewegung der Maus selbst. Wir können diesen Ereignissen benutzerdefinierte Aktionen zuordnen, was die Möglichkeiten eines HTML-Dokuments erheblich erweitert.
Das wahrscheinlich offensichtlichste HTML-Element in Verbindung mit einer zugehörigen Aktion ist das Element button
. Um zu zeigen, wie es funktioniert, fügen Sie drei Schaltflächen über dem ersten div
-Element der Beispielseite ein:
<p>
<button>First</button>
<button>Second</button>
<button>Third</button>
</p>
<div class="content" id="content_first">
<p>First section.</p>
</div><!-- #content_first -->
<div class="content" id="content_second">
<p>Second section.</p>
</div><!-- #content_second -->
<div class="content" id="content_third">
<p>Third section.</p>
</div><!-- #content_third -->
Die Schaltflächen tun von sich aus nichts. Wollen Sie aber beispielsweise das div
, das der gedrückten Schaltfläche entspricht, hervorheben, weisen Sie über das Attribut onClick
jeder Schaltfläche eine Aktion zu:
<p>
<button onClick="document.getElementById('content_first').classList.toggle('highlight')">First</button>
<button onClick="document.getElementById('content_second').classList.toggle('highlight')">Second</button>
<button onClick="document.getElementById('content_third').classList.toggle('highlight')">Third</button>
</p>
Die Methode classList.toggle()
fügt dem Element die angegebene Klasse hinzu, wenn sie nicht vorhanden ist, und entfernt sie, wenn sie bereits vorhanden ist. Wenn Sie das Beispiel ausführen, werden Sie feststellen, dass mehr als ein div
gleichzeitig hervorgehoben werden kann. Um nur das div
hervorzuheben, das der gedrückten Schaltfläche entspricht, ist es notwendig, die Klasse highlight
aus den anderen div
-Elementen zu entfernen. Wenn die benutzerdefinierte Aktion jedoch zu lang ist oder mehr als eine Codezeile umfasst, ist es praktischer, eine Funktion außerhalb des Element-Tags zu schreiben:
function highlight(id)
{
// Remove the "highlight" class from all content elements
for ( element of document.querySelectorAll(".content") )
{
element.classList.remove('highlight');
}
// Add the "highlight" class to the corresponding element
document.getElementById(id).classList.add('highlight');
}
Wie in den vorangegangenen Beispielen können Sie diese Funktion innerhalb eines <script>
-Tags oder in einer externen, mit dem Dokument verbundenen JavaScript-Datei platzieren. Die Funktion highlight
entfernt zunächst die Klasse highlight
aus allen div
-Elementen, die mit der Klasse content
verbunden sind, und fügt dann die Klasse highlight
dem ausgewählten Element hinzu. Jede Schaltfläche sollte dann diese Funktion über ihr onClick
-Attribut aufrufen, wobei die entsprechende ID als Argument der Funktion verwendet wird:
<p>
<button onClick="highlight('content_first')">First</button>
<button onClick="highlight('content_second')">Second</button>
<button onClick="highlight('content_third')">Third</button>
</p>
Neben dem Attribut onClick
könnten wir das Attribut onMouseOver
verwenden (ausgelöst, wenn das Zeigegerät den Cursor auf das Element bewegt), das Attribut onMouseOut
(ausgelöst, wenn das Zeigegerät nicht mehr im Element ist) usw. Außerdem sind die Event Handler nicht auf Schaltflächen beschränkt, so dass Sie diesen Event Handlern für alle sichtbaren HTML-Elemente benutzerdefinierte Aktionen zuweisen können.
Geführte Übungen
-
Wie fügen Sie mit der Methode
document.getElementById()
den Text “Dynamic content” in den inneren Inhalt des Elements mit der IDmessage
ein? -
Was ist der Unterschied zwischen der Referenzierung eines Elements über seine ID mit der Methode
document.querySelector()
und der Referenzierung über die Methodedocument.getElementById()
? -
Was ist der Zweck der Methode
classList.remove()
? -
Was bewirkt die Methode
myelement.classList.toggle("active")
, wennmyelement
nicht die Klasseactive
zugewiesen ist?
Offene Übungen
-
Welches Argument für die Methode
document.querySelectorAll()
bewirkt, dass sie die Methodedocument.getElementsByTagName("input")
nachahmt? -
Wie nutzen Sie die Eigenschaft
classList
, um alle Klassen aufzulisten, die mit einem bestimmten Element verbunden sind?
Zusammenfassung
In dieser Lektion haben Sie gelernt, wie Sie mit JavaScript HTML-Inhalte und deren CSS-Eigenschaften mithilfe des DOM (Document Object Model) ändern. Diese Änderungen können durch Benutzerereignisse ausgelöst werden, was für die Erstellung dynamischer Schnittstellen nützlich ist. In dieser Lektion werden die folgenden Konzepte und Verfahren behandelt:
-
Wie man die Struktur des Dokuments mit Methoden wie
document.getElementById()
,document.getElementsByClassName()
,document.getElementsByTagName()
,document.querySelector()
unddocument.querySelectorAll()
untersucht. -
Wie man den Inhalt des Dokuments mit der Eigenschaft
innerHTML
ändert. -
Wie man die Attribute von Seitenelementen mit den Methoden
setAttribute()
undremoveAttribute()
hinzufügt und ändert. -
Die richtige Art und Weise, Elementklassen mit der Eigenschaft
classList
zu manipulieren und ihre Beziehung zu CSS-Stilen. -
Wie man Funktionen an Maus-Ereignisse in bestimmten Elementen bindet.
Lösungen zu den geführten Übungen
-
Wie fügen Sie mit der Methode
document.getElementById()
den Text “Dynamic content” in den inneren Inhalt des Elements mit der IDmessage
ein?Mit der Eigenschaft
innerHTML
:document.getElementById("message").innerHTML = "Dynamic content"
-
Was ist der Unterschied zwischen der Referenzierung eines Elements über seine ID mit der Methode
document.querySelector()
und der Referenzierung über die Methodedocument.getElementById()
?Die ID muss in Funktionen, die Selektoren verwenden, wie z.B.
document.querySelector()
, mit dem Rautezeichen versehen werden. -
Was ist der Zweck der Methode
classList.remove()
?Sie entfernt die Klasse (deren Name als Argument der Funktion angegeben wird) aus dem Attribut
class
des entsprechenden Elements. -
Was bewirkt die Methode
myelement.classList.toggle("active")
, wennmyelement
nicht die Klasseactive
zugewiesen ist?Die Methode weist
myelement
die Klasseactive
zu.
Lösungen zu den offenen Übungen
-
Welches Argument für die Methode
document.querySelectorAll()
bewirkt, dass sie die Methodedocument.getElementsByTagName("input")
nachahmt?document.querySelectorAll("input")
passt auf alleinput
-Elemente der Seite, genau wiedocument.getElementsByTagName("input")
. -
Wie nutzen Sie die Eigenschaft
classList
, um alle Klassen aufzulisten, die mit einem bestimmten Element verbunden sind?Die Eigenschaft
classList
ist ein Array-ähnliches Objekt, so dass mit einerfor
-Schleife alle darin enthaltenen Klassen durchlaufen werden können.