15 KiB
Terrarium-Projekt Teil 3: DOM-Manipulation und eine Closure
Sketchnote von Tomomi Imura
Quiz vor der Vorlesung
Einführung
Die Manipulation des DOM, oder des "Document Object Model", ist ein zentraler Aspekt der Webentwicklung. Laut MDN ist "Das Document Object Model (DOM) die Datenrepräsentation der Objekte, die die Struktur und den Inhalt eines Dokuments im Web ausmachen." Die Herausforderungen rund um die DOM-Manipulation im Web haben oft dazu geführt, dass JavaScript-Frameworks anstelle von Vanilla-JavaScript verwendet werden, um das DOM zu verwalten. Aber wir werden es selbst schaffen!
Darüber hinaus wird in dieser Lektion die Idee einer JavaScript-Closure eingeführt, die man sich als eine Funktion vorstellen kann, die von einer anderen Funktion umschlossen ist, sodass die innere Funktion Zugriff auf den Scope der äußeren Funktion hat.
JavaScript-Closures sind ein umfangreiches und komplexes Thema. Diese Lektion behandelt die grundlegende Idee, dass im Code dieses Terrariums eine Closure zu finden ist: eine innere Funktion und eine äußere Funktion, die so konstruiert sind, dass die innere Funktion Zugriff auf den Scope der äußeren Funktion hat. Für weitere Informationen darüber, wie dies funktioniert, besuchen Sie bitte die ausführliche Dokumentation.
Wir werden eine Closure verwenden, um das DOM zu manipulieren.
Stellen Sie sich das DOM als einen Baum vor, der alle Möglichkeiten darstellt, wie ein Webseitendokument manipuliert werden kann. Verschiedene APIs (Application Program Interfaces) wurden entwickelt, damit Programmierer mit ihrer bevorzugten Programmiersprache auf das DOM zugreifen und es bearbeiten, ändern, umorganisieren und anderweitig verwalten können.
Eine Darstellung des DOM und des HTML-Markups, das darauf verweist. Von Olfa Nasraoui
In dieser Lektion werden wir unser interaktives Terrarium-Projekt abschließen, indem wir das JavaScript erstellen, das es einem Benutzer ermöglicht, die Pflanzen auf der Seite zu manipulieren.
Voraussetzung
Sie sollten das HTML und CSS für Ihr Terrarium erstellt haben. Am Ende dieser Lektion werden Sie in der Lage sein, die Pflanzen durch Ziehen in und aus dem Terrarium zu bewegen.
Aufgabe
Erstellen Sie in Ihrem Terrarium-Ordner eine neue Datei namens script.js
. Importieren Sie diese Datei im <head>
-Abschnitt:
<script src="./script.js" defer></script>
Hinweis: Verwenden Sie
defer
, wenn Sie eine externe JavaScript-Datei in die HTML-Datei importieren, damit das JavaScript erst ausgeführt wird, nachdem die HTML-Datei vollständig geladen wurde. Sie könnten auch dasasync
-Attribut verwenden, das es dem Skript ermöglicht, während des Parsens der HTML-Datei ausgeführt zu werden. In unserem Fall ist es jedoch wichtig, dass die HTML-Elemente vollständig verfügbar sind, bevor wir das Drag-Skript ausführen.
Die DOM-Elemente
Das erste, was Sie tun müssen, ist, Referenzen zu den Elementen zu erstellen, die Sie im DOM manipulieren möchten. In unserem Fall sind dies die 14 Pflanzen, die derzeit in den Seitenleisten warten.
Aufgabe
dragElement(document.getElementById('plant1'));
dragElement(document.getElementById('plant2'));
dragElement(document.getElementById('plant3'));
dragElement(document.getElementById('plant4'));
dragElement(document.getElementById('plant5'));
dragElement(document.getElementById('plant6'));
dragElement(document.getElementById('plant7'));
dragElement(document.getElementById('plant8'));
dragElement(document.getElementById('plant9'));
dragElement(document.getElementById('plant10'));
dragElement(document.getElementById('plant11'));
dragElement(document.getElementById('plant12'));
dragElement(document.getElementById('plant13'));
dragElement(document.getElementById('plant14'));
Was passiert hier? Sie referenzieren das Dokument und durchsuchen dessen DOM, um ein Element mit einer bestimmten Id zu finden. Erinnern Sie sich an die erste Lektion über HTML, in der Sie jedem Pflanzenbild individuelle Ids zugewiesen haben (id="plant1"
)? Jetzt werden Sie diese Arbeit nutzen. Nachdem Sie jedes Element identifiziert haben, übergeben Sie dieses Element an eine Funktion namens dragElement
, die Sie gleich erstellen werden. Somit ist das Element im HTML jetzt drag-fähig oder wird es gleich sein.
✅ Warum referenzieren wir Elemente nach Id? Warum nicht nach ihrer CSS-Klasse? Sie könnten auf die vorherige Lektion über CSS zurückgreifen, um diese Frage zu beantworten.
Die Closure
Jetzt sind Sie bereit, die dragElement
-Closure zu erstellen, die eine äußere Funktion ist, die eine innere Funktion oder mehrere umschließt (in unserem Fall werden es drei sein).
Closures sind nützlich, wenn eine oder mehrere Funktionen Zugriff auf den Scope einer äußeren Funktion benötigen. Hier ist ein Beispiel:
function displayCandy(){
let candy = ['jellybeans'];
function addCandy(candyType) {
candy.push(candyType)
}
addCandy('gumdrops');
}
displayCandy();
console.log(candy)
In diesem Beispiel umgibt die Funktion displayCandy
eine Funktion, die eine neue Süßigkeit in ein Array einfügt, das bereits in der Funktion existiert. Wenn Sie diesen Code ausführen würden, wäre das candy
-Array undefiniert, da es eine lokale Variable ist (lokal zur Closure).
✅ Wie können Sie das candy
-Array zugänglich machen? Versuchen Sie, es außerhalb der Closure zu verschieben. Auf diese Weise wird das Array global, anstatt nur im lokalen Scope der Closure verfügbar zu sein.
Aufgabe
Erstellen Sie unter den Elementdeklarationen in script.js
eine Funktion:
function dragElement(terrariumElement) {
//set 4 positions for positioning on the screen
let pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
terrariumElement.onpointerdown = pointerDrag;
}
dragElement
erhält sein terrariumElement
-Objekt aus den Deklarationen am Anfang des Skripts. Dann setzen Sie einige lokale Positionen auf 0
für das Objekt, das in die Funktion übergeben wird. Dies sind die lokalen Variablen, die für jedes Element manipuliert werden, während Sie Drag-and-Drop-Funktionalität innerhalb der Closure zu jedem Element hinzufügen. Das Terrarium wird von diesen gezogenen Elementen bevölkert, sodass die Anwendung verfolgen muss, wo sie platziert werden.
Darüber hinaus wird das terrariumElement
, das an diese Funktion übergeben wird, einem pointerdown
-Event zugewiesen, das Teil der Web-APIs ist, die zur Unterstützung der DOM-Verwaltung entwickelt wurden. onpointerdown
wird ausgelöst, wenn eine Taste gedrückt wird oder in unserem Fall ein ziehbares Element berührt wird. Dieser Event-Handler funktioniert sowohl auf Web- als auch auf mobilen Browsern, mit einigen Ausnahmen.
✅ Der Event-Handler onclick
hat eine viel größere Unterstützung über verschiedene Browser hinweg; warum würden Sie ihn hier nicht verwenden? Denken Sie über die genaue Art der Bildschirminteraktion nach, die Sie hier erstellen möchten.
Die Pointerdrag-Funktion
Das terrariumElement
ist bereit, herumgezogen zu werden; wenn das onpointerdown
-Event ausgelöst wird, wird die Funktion pointerDrag
aufgerufen. Fügen Sie diese Funktion direkt unter dieser Zeile hinzu: terrariumElement.onpointerdown = pointerDrag;
:
Aufgabe
function pointerDrag(e) {
e.preventDefault();
console.log(e);
pos3 = e.clientX;
pos4 = e.clientY;
}
Es passieren mehrere Dinge. Erstens verhindern Sie die Standardereignisse, die normalerweise bei pointerdown
auftreten, indem Sie e.preventDefault();
verwenden. Auf diese Weise haben Sie mehr Kontrolle über das Verhalten der Benutzeroberfläche.
Kehren Sie zu dieser Zeile zurück, wenn Sie die Skriptdatei vollständig erstellt haben, und versuchen Sie es ohne
e.preventDefault()
- was passiert?
Zweitens öffnen Sie index.html
in einem Browserfenster und inspizieren die Benutzeroberfläche. Wenn Sie auf eine Pflanze klicken, können Sie sehen, wie das 'e'-Event erfasst wird. Untersuchen Sie das Event, um zu sehen, wie viele Informationen durch ein einziges pointerdown
-Event gesammelt werden!
Als Nächstes beachten Sie, wie die lokalen Variablen pos3
und pos4
auf e.clientX
gesetzt werden. Sie können die e
-Werte im Inspektionsfenster finden. Diese Werte erfassen die x- und y-Koordinaten der Pflanze in dem Moment, in dem Sie darauf klicken oder sie berühren. Sie benötigen eine feingranulare Kontrolle über das Verhalten der Pflanzen, während Sie sie klicken und ziehen, daher verfolgen Sie ihre Koordinaten.
✅ Wird es klarer, warum diese gesamte App mit einer großen Closure erstellt wurde? Wenn nicht, wie würden Sie den Scope für jede der 14 ziehbaren Pflanzen aufrechterhalten?
Vervollständigen Sie die Anfangsfunktion, indem Sie zwei weitere Pointer-Event-Manipulationen unter pos4 = e.clientY
hinzufügen:
document.onpointermove = elementDrag;
document.onpointerup = stopElementDrag;
Jetzt geben Sie an, dass Sie möchten, dass die Pflanze zusammen mit dem Zeiger bewegt wird, während Sie sie ziehen, und dass die Ziehbewegung stoppt, wenn Sie die Pflanze abwählen. onpointermove
und onpointerup
sind alle Teil derselben API wie onpointerdown
. Die Benutzeroberfläche wird jetzt Fehler werfen, da Sie die Funktionen elementDrag
und stopElementDrag
noch nicht definiert haben. Erstellen Sie diese als Nächstes.
Die Funktionen elementDrag und stopElementDrag
Sie werden Ihre Closure vervollständigen, indem Sie zwei weitere interne Funktionen hinzufügen, die steuern, was passiert, wenn Sie eine Pflanze ziehen und das Ziehen beenden. Das gewünschte Verhalten ist, dass Sie jederzeit jede Pflanze ziehen und sie überall auf dem Bildschirm platzieren können. Diese Benutzeroberfläche ist ziemlich unvoreingenommen (es gibt beispielsweise keine Drop-Zone), um Ihnen zu ermöglichen, Ihr Terrarium genau so zu gestalten, wie Sie es möchten, indem Sie Pflanzen hinzufügen, entfernen und neu positionieren.
Aufgabe
Fügen Sie die Funktion elementDrag
direkt nach der schließenden geschweiften Klammer von pointerDrag
hinzu:
function elementDrag(e) {
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
console.log(pos1, pos2, pos3, pos4);
terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px';
terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px';
}
In dieser Funktion bearbeiten Sie viele der Anfangspositionen 1-4, die Sie als lokale Variablen in der äußeren Funktion gesetzt haben. Was passiert hier?
Während Sie ziehen, weisen Sie pos1
neu zu, indem Sie es gleich pos3
setzen (das Sie zuvor als e.clientX
gesetzt haben), minus dem aktuellen e.clientX
-Wert. Sie führen eine ähnliche Operation für pos2
durch. Dann setzen Sie pos3
und pos4
auf die neuen X- und Y-Koordinaten des Elements zurück. Sie können diese Änderungen in der Konsole beobachten, während Sie ziehen. Dann manipulieren Sie den CSS-Stil der Pflanze, um ihre neue Position basierend auf den neuen Positionen von pos1
und pos2
zu setzen, indem Sie die oberen und linken X- und Y-Koordinaten der Pflanze basierend auf ihrem Offset mit diesen neuen Positionen berechnen.
offsetTop
undoffsetLeft
sind CSS-Eigenschaften, die die Position eines Elements basierend auf der seines Elternteils setzen; das Elternteil kann jedes Element sein, das nicht alsstatic
positioniert ist.
All diese Neuberechnung der Positionierung ermöglicht es Ihnen, das Verhalten des Terrariums und seiner Pflanzen fein abzustimmen.
Aufgabe
Die letzte Aufgabe, um die Benutzeroberfläche zu vervollständigen, besteht darin, die Funktion stopElementDrag
nach der schließenden geschweiften Klammer von elementDrag
hinzuzufügen:
function stopElementDrag() {
document.onpointerup = null;
document.onpointermove = null;
}
Diese kleine Funktion setzt die onpointerup
- und onpointermove
-Events zurück, sodass Sie entweder den Fortschritt Ihrer Pflanze neu starten können, indem Sie sie erneut ziehen, oder beginnen können, eine neue Pflanze zu ziehen.
✅ Was passiert, wenn Sie diese Events nicht auf null setzen?
Jetzt haben Sie Ihr Projekt abgeschlossen!
🥇Herzlichen Glückwunsch! Sie haben Ihr wunderschönes Terrarium fertiggestellt.
🚀Herausforderung
Fügen Sie Ihrer Closure einen neuen Event-Handler hinzu, um etwas mehr mit den Pflanzen zu machen; zum Beispiel, doppelklicken Sie auf eine Pflanze, um sie in den Vordergrund zu bringen. Werden Sie kreativ!
Quiz nach der Vorlesung
Überprüfung & Selbststudium
Obwohl das Ziehen von Elementen über den Bildschirm trivial erscheint, gibt es viele Möglichkeiten, dies zu tun, und viele Fallstricke, abhängig von dem gewünschten Effekt. Tatsächlich gibt es eine gesamte Drag-and-Drop-API, die Sie ausprobieren können. Wir haben sie in diesem Modul nicht verwendet, da der gewünschte Effekt etwas anders war, aber probieren Sie diese API in Ihrem eigenen Projekt aus und sehen Sie, was Sie erreichen können.
Weitere Informationen zu Pointer-Events finden Sie in den W3C-Dokumenten und in den MDN-Web-Dokumenten.
Überprüfen Sie immer die Browser-Fähigkeiten mit CanIUse.com.
Aufgabe
Arbeiten Sie ein wenig mehr mit dem DOM
Haftungsausschluss:
Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner ursprünglichen Sprache sollte als maßgebliche Quelle betrachtet werden. Für kritische Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die sich aus der Nutzung dieser Übersetzung ergeben.