Wie kann man eine To-Do-App mit Vanilla JavaScript erstellen (und lokalem Speicher)?
German (Deutsch) translation by Katharina Grigorovich-Nevolina (you can also view the original English article)
In diesem Tutorial werden wir unsere Front-End-Fähigkeiten verbessern, indem wir lernen, eine „handgemachte“ To-Do-App zu erstellen. Zum Erstellen werden keine JavaScript-Frameworks verwendet. Wir verwenden nur HTML, CSS und Vanille-JavaScript.
Was werden wir erstellen?
Hier ist ein Einführungsvideo, das die Funktionalität der JavaScript-App demonstriert, die wir erstellen werden. Benutzer können Aufgaben hinzufügen, als erledigt markieren und entfernen. Die Aufgabensummen und ihre Status werden in der Statusleiste angezeigt:
Hier ist die Demo zu Codepen, mit der Sie spielen können:
Hinweis: Dies ist kein Einführungs-Tutorial. Es wird davon ausgegangen, dass Sie mit den wichtigsten Front-End-Kenntnissen wie CSS Grid, Flexbox, ES6, JavaScript-Arrays usw. vertraut sind. Für diese Demonstration hat es auch keine Priorität, die App vollständig zugänglich zu machen.
1. Beginnen Sie mit den erforderlichen Assets
Um das Layout ein bisschen einzigartiger zu gestalten, verwenden wir einige handgefertigte SVG-Illustrationen und eine benutzerdefinierte Schriftart aus Envato Elements.


Es ist erwähnenswert, dass die meisten dieser Assets aus einem früheren Tutorial stammen. Tatsächlich werden wir auch viele der Positionierungstechniken verwenden, die wir in diesem Tutorial gelernt haben. Es lohnt sich also, sie zu lesen.



2. Weiter mit der Seiten-Markup
Wir beginnen mit einer SVG und einem div-Container:
1 |
<svg style="display:none;">...</svg> |
2 |
<div class="container">...</div> |
SVG Sprites
Wie schon in der Vergangenheit haben wir als bewährte Methode alle SVGs als symbols in einem SVG-Sprite-Container gespeichert. Anschließend rendern wir sie bei Bedarf auf dem Bildschirm, indem wir das use-Element aufrufen.
Hier ist das Markup für das SVG-Sprite:
1 |
<svg style="display:none;"> |
2 |
<symbol id="input" viewBox="0 0 345.27 56.51" preserveAspectRatio="none">...</symbol> |
3 |
<symbol id="checkbox_empty" viewBox="0 0 33.18 33.34">...</symbol> |
4 |
<symbol id="checkmark" viewBox="0 0 37.92 33.3" preserveAspectRatio="none">...</symbol> |
5 |
<symbol id="button" viewBox="0 0 256.6 60.02" preserveAspectRatio="none">...</symbol> |
6 |
<symbol id="close" viewBox="0 0 29.71 30.59">...</symbol> |
7 |
<symbol id="stats" viewBox="0 0 998.06 602.62" preserveAspectRatio="none">...</symbol> |
8 |
</svg>
|
Beachten Sie das preserveAttributerveAspectRatio="none", das wir den meisten Abbildungen beigefügt haben. Wir haben dies getan, da unsere Symbole, wie wir später sehen werden, skaliert werden und ihre ursprünglichen Abmessungen verlieren.
Container
Der Container enthält ein Formular, ein div-Element und eine leere geordnete Liste:
1 |
<div class="container"> |
2 |
<form class="todo-form">...</form> |
3 |
<div class="todo-stats">...</div> |
4 |
<ol class="todo-list"></ol> |
5 |
</div>
|
Innerhalb des Formulars haben wir eine Eingabe- und eine Senden-Schaltfläche zusammen mit den zugehörigen SVGs:
1 |
<form class="todo-form"> |
2 |
<div class="form-wrapper"> |
3 |
<input type="text" name="name" autofocus> |
4 |
<svg>
|
5 |
<use xlink:href="#input"></use> |
6 |
</svg>
|
7 |
</div>
|
8 |
<div class="form-wrapper"> |
9 |
<button type="submit">Add new task</button> |
10 |
<svg>
|
11 |
<use xlink:href="#button"></use> |
12 |
</svg>
|
13 |
</div>
|
14 |
</form>
|
Beachten Sie das name-Attribut, das wir dem Eingabefeld hinzugefügt haben. Später verwenden wir dieses Attribut, um nach dem Absenden des Formulars auf den Eingabewert zuzugreifen.
Hinweis: In unserer Demo funktioniert das autofocus-Attribut des Textfelds nicht. Tatsächlich wird der folgende Fehler ausgegeben, den Sie sehen können, wenn Sie Ihre Browserkonsole öffnen:



Wenn Sie diese App jedoch lokal ausführen (nicht als Codepen-Projekt), tritt dieses Problem nicht auf. Alternativ können Sie den Fokus über JavaScript festlegen.
Innerhalb des div platzieren wir drei verschachtelte divs und das zugehörige SVG. In diesem Abschnitt verfolgen wir die Gesamtzahl der verbleibenden und erledigten Aufgaben:
1 |
<div class="todo-stats"> |
2 |
<div class="total-tasks"> |
3 |
Total Tasks: <span>0</span> |
4 |
</div>
|
5 |
<div class="completed-tasks"> |
6 |
Completed Tasks: <span>0</span> |
7 |
</div>
|
8 |
<div class="remaining-tasks"> |
9 |
Remaining Tasks: <span>0</span> |
10 |
</div>
|
11 |
<svg>
|
12 |
<use xlink:href="#stats"></use> |
13 |
</svg>
|
14 |
</div>
|
Schließlich werden die Elemente der geordneten Liste dynamisch über JavaScript hinzugefügt.
3. Definieren Sie einige grundlegende Stile
Wenn das Markup fertig ist, fahren wir mit einigen Reset-Stilen fort:
1 |
@font-face { |
2 |
font-family: "Summer"; |
3 |
src: url(SummerFont-Regular.woff); |
4 |
}
|
5 |
|
6 |
@font-face { |
7 |
font-family: "Summer Bold"; |
8 |
src: url(SummerFont-Bold.woff); |
9 |
}
|
10 |
|
11 |
:root { |
12 |
--white: #fff; |
13 |
}
|
14 |
|
15 |
* { |
16 |
padding: 0; |
17 |
margin: 0; |
18 |
border: none; |
19 |
outline: none; |
20 |
box-sizing: border-box; |
21 |
}
|
22 |
|
23 |
input, |
24 |
button { |
25 |
font-family: inherit; |
26 |
font-size: 100%; |
27 |
background: none; |
28 |
}
|
29 |
|
30 |
[type="checkbox"] { |
31 |
position: absolute; |
32 |
left: -9999px; |
33 |
}
|
34 |
|
35 |
button, |
36 |
label { |
37 |
cursor: pointer; |
38 |
}
|
39 |
|
40 |
ol { |
41 |
list-style: none; |
42 |
}
|
43 |
|
44 |
body { |
45 |
font: 28px/1.2 "Summer"; |
46 |
margin: 1.5rem 0; |
47 |
}
|
4. Legen Sie die Hauptstile fest
Lassen Sie uns nun die Hauptstile unserer App diskutieren.
Containerstile
Der Container hat eine maximale Breite mit horizontal zentriertem Inhalt:
1 |
.container { |
2 |
max-width: 700px; |
3 |
padding: 0 10px; |
4 |
margin: 0 auto; |
5 |
}
|
Formularstile
Auf kleinen Bildschirmen werden alle Formularelemente gestapelt:



In Ansichtsfenstern mit einer Breite von 600 Pixel und mehr ändert sich das Formularlayout jedoch wie folgt:



Beachten wir zwei Dinge:
- In weiten Ansichtsfenstern ist die Eingabe doppelt so groß wie die Schaltfläche.
- Die SVGs sind absolut positionierte Elemente und befinden sich unter ihrer angrenzenden Formularsteuerung. Eine ausführlichere Erklärung finden Sie in diesem vorherigen Tutorial.
Hier sind die Stile für diesen Abschnitt:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.todo-form .form-wrapper { |
4 |
position: relative; |
5 |
}
|
6 |
|
7 |
.todo-form input, |
8 |
.todo-form button { |
9 |
position: relative; |
10 |
width: 100%; |
11 |
z-index: 1; |
12 |
padding: 15px; |
13 |
}
|
14 |
|
15 |
.todo-form svg { |
16 |
position: absolute; |
17 |
top: 0; |
18 |
left: 0; |
19 |
width: 100%; |
20 |
height: 100%; |
21 |
}
|
22 |
|
23 |
.todo-form button { |
24 |
color: var(--white); |
25 |
text-transform: uppercase; |
26 |
}
|
27 |
|
28 |
@media screen and (min-width: 600px) { |
29 |
.todo-form { |
30 |
display: grid; |
31 |
grid-template-columns: 2fr 1fr; |
32 |
grid-column-gap: 5px; |
33 |
}
|
34 |
}
|
Statistik Stile
Schauen wir uns als nächstes die Statusleiste an, die uns einen kurzen Bericht über die Gesamtzahl der Aufgaben gibt.
Auf kleinen Bildschirmen sieht es wie folgt aus:



Bei Ansichtsfenstern mit einer Breite von 600 Pixel und mehr sollte sich dies jedoch wie folgt ändern:



Beachten wir zwei Dinge:
- In breiten Ansichtsfenstern haben alle untergeordneten
div-Elemente die gleiche Breite. - Ähnlich wie bei den vorherigen SVGs ist auch diese absolut positioniert und fungiert als Hintergrundbild, das den gesamten Abschnitt abdeckt.
Die verwandten Stile:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.todo-stats { |
4 |
position: relative; |
5 |
text-align: center; |
6 |
padding: 5px 10px; |
7 |
margin: 10px 0; |
8 |
color: var(--white); |
9 |
}
|
10 |
|
11 |
.todo-stats > div { |
12 |
position: relative; |
13 |
z-index: 1; |
14 |
}
|
15 |
|
16 |
.todo-stats svg { |
17 |
position: absolute; |
18 |
top: 0; |
19 |
left: 0; |
20 |
width: 100%; |
21 |
height: 100%; |
22 |
}
|
23 |
|
24 |
@media screen and (min-width: 600px) { |
25 |
.todo-stats { |
26 |
display: grid; |
27 |
grid-template-columns: repeat(3, 1fr); |
28 |
}
|
29 |
}
|
Aufgabenstile
Das Aufgabenlayout, das wir im nächsten Abschnitt dynamisch generieren, sieht folgendermaßen aus:



Jede Aufgabe, die durch ein li dargestellt wird, besteht aus zwei Teilen.



Im ersten Teil wird ein Kontrollkästchen zusammen mit dem Aufgabennamen angezeigt. Im zweiten Teil sehen Sie eine Schaltfläche zum Löschen, um die Aufgabe zu entfernen.
Hier sind die verwandten Stile:
1 |
.todo-list li { |
2 |
display: grid; |
3 |
align-items: baseline; |
4 |
grid-template-columns: auto 20px; |
5 |
grid-column-gap: 10px; |
6 |
padding: 0 10px; |
7 |
}
|
8 |
|
9 |
.todo-list li + li { |
10 |
margin-top: 10px; |
11 |
}
|
Wenn eine Aufgabe unvollständig ist, wird ein leeres Kontrollkästchen angezeigt. Wenn eine Aufgabe als erledigt markiert ist, wird ein Häkchen angezeigt. Zusätzlich erhält der Name eine Deckkraft von 50% sowie eine Linie durch ihn.
Hier sind die Stile, die für dieses Verhalten verantwortlich sind:
1 |
.todo-list .checkbox-wrapper { |
2 |
display: flex; |
3 |
align-items: baseline; |
4 |
}
|
5 |
|
6 |
.todo-list .checkbox-wrapper label { |
7 |
display: grid; |
8 |
margin-right: 10px; |
9 |
}
|
10 |
|
11 |
.todo-list .checkbox-wrapper svg { |
12 |
grid-column: 1; |
13 |
grid-row: 1; |
14 |
width: 20px; |
15 |
height: 20px; |
16 |
}
|
17 |
|
18 |
.todo-list .checkbox-wrapper .checkmark { |
19 |
display: none; |
20 |
}
|
21 |
|
22 |
.todo-list [type="checkbox"]:checked + label .checkmark { |
23 |
display: block; |
24 |
}
|
25 |
|
26 |
.todo-list [type="checkbox"]:checked ~ span { |
27 |
text-decoration: line-through; |
28 |
opacity: 0.5; |
29 |
}
|
Im Folgenden finden Sie die Stile für die Schaltfläche "Löschen":
1 |
.todo-list .remove-task { |
2 |
display: flex; |
3 |
padding: 2px; |
4 |
}
|
5 |
|
6 |
.todo-list .remove-task svg { |
7 |
width: 16px; |
8 |
height: 16px; |
9 |
}
|
5. Fügen Sie das JavaScript hinzu
An diesem Punkt sind wir bereit, die Kernfunktionalität unserer App zu erstellen. Lassen Sie es uns tun!
Beim Einreichen des Formulars
Jedes Mal, wenn ein Benutzer das Formular durch Drücken der Eingabetaste oder der Schaltfläche "Senden" sendet, gehen wir wie folgt vor:
- Verhindern Sie das Senden des Formulars, wodurch ein erneutes Laden der Seite verhindert wird.
- Holen Sie sich den Wert, der im Eingabefeld enthalten ist.
- Angenommen, das Eingabefeld ist nicht leer, erstellen wir ein neues Objektliteral, das die Aufgabe darstellt. Jede Aufgabe hat eine eindeutige ID und einen Namen und ist standardmäßig aktiv (nicht abgeschlossen).
- Fügen Sie diese Aufgabe dem
tasks-Array hinzu. - Speichern Sie das Array im lokalen Speicher. Der lokale Speicher unterstützt nur Zeichenfolgen. Dazu müssen wir die Methode
JSON.stringify()verwenden, um die Objekte im Array in Zeichenfolgen zu konvertieren. - Rufen Sie die Funktion
createTask()auf, um die Aufgabe auf dem Bildschirm visuell darzustellen. - Löschen Sie das Formular.
- Konzentrieren Sie sich auf das Eingabefeld.
Hier ist der relevante Code:
1 |
const todoForm = document.querySelector(".todo-form"); |
2 |
let tasks = []; |
3 |
|
4 |
todoForm.addEventListener("submit", function(e) { |
5 |
// 1
|
6 |
e.preventDefault(); |
7 |
// 2
|
8 |
const input = this.name; |
9 |
const inputValue = input.value; |
10 |
|
11 |
if (inputValue != "") { |
12 |
// 3
|
13 |
const task = { |
14 |
id: new Date().getTime(), |
15 |
name: inputValue, |
16 |
isCompleted: false |
17 |
};
|
18 |
// 4
|
19 |
tasks.push(task); |
20 |
// 5
|
21 |
localStorage.setItem("tasks", JSON.stringify(tasks)); |
22 |
// 6
|
23 |
createTask(task); |
24 |
// 7
|
25 |
todoForm.reset(); |
26 |
}
|
27 |
// 8
|
28 |
input.focus(); |
29 |
});
|
Erstellen Sie eine Aufgabe
Die Funktion createTask() ist für die Erstellung des Markups der Aufgabe verantwortlich.
Hier ist zum Beispiel die Struktur für die Aufgabe "Go for a walk":



Zwei Dinge sind hier wichtig:
- Wenn die Aufgabe abgeschlossen ist, wird das Häkchen angezeigt.
- Wenn die Aufgabe nicht abgeschlossen ist, erhält das
span-Element das Attributcontenteditable. Dieses Attribut gibt uns die Möglichkeit, seinen Namen zu bearbeiten/aktualisieren.
Unten ist die Syntax für diese Funktion:
1 |
function createTask(task) { |
2 |
const taskEl = document.createElement("li"); |
3 |
taskEl.setAttribute("id", task.id); |
4 |
const taskElMarkup = ` |
5 |
<div class="checkbox-wrapper">
|
6 |
<input type="checkbox" id="${task.name}-${task.id}" name="tasks" ${ |
7 |
task.isCompleted ? "checked" : "" |
8 |
}> |
9 |
<label for="${task.name}-${task.id}"> |
10 |
<svg class="checkbox-empty">
|
11 |
<use xlink:href="#checkbox_empty"></use>
|
12 |
</svg>
|
13 |
<svg class="checkmark">
|
14 |
<use xlink:href="#checkmark"></use>
|
15 |
</svg>
|
16 |
</label>
|
17 |
<span ${!task.isCompleted ? "contenteditable" : ""}>${task.name}</span> |
18 |
</div>
|
19 |
<button class="remove-task" title="Remove ${task.name} task"> |
20 |
<svg>
|
21 |
<use xlink:href="#close"></use>
|
22 |
</svg>
|
23 |
</button>
|
24 |
`; |
25 |
taskEl.innerHTML = taskElMarkup; |
26 |
todoList.appendChild(taskEl); |
27 |
countTasks(); |
28 |
}
|
Aktualisieren Sie eine Aufgabe
Eine Aufgabe kann auf zwei verschiedene Arten aktualisiert werden:
- Durch Ändern des Status von "unvollständig" in "abgeschlossen" und umgekehrt.
- Durch Ändern des Namens für den Fall, dass die Aufgabe unvollständig ist. Denken Sie daran, dass in diesem Fall das
span-Element das Attributcontenteditablehat.
Um diese Änderungen im Auge zu behalten, nutzen wir das input-Ereignis. Dies ist ein akzeptables Ereignis für uns, da es sowohl für input-Elemente als auch für Elemente mit aktiviertem contenteditable gilt.
Das Schwierige ist, dass wir dieses Ereignis nicht direkt an die Zielelemente (Kontrollkästchen, span) anhängen können, da diese dynamisch erstellt werden und beim Laden der Seite nicht Teil des DOM sind.
Dank der Ereignisdelegation hängen wir das input-Ereignis an die übergeordnete Liste an, die Teil des anfänglichen Markups ist. Anschließend überprüfen wir über die target-Eigenschaft dieses Ereignisses die Elemente, bei denen das Ereignis aufgetreten ist, und rufen die Funktion updateTask() auf:
1 |
todoList.addEventListener("input", (e) => { |
2 |
const taskId = e.target.closest("li").id; |
3 |
updateTask(taskId, e.target); |
4 |
});
|
In der Funktion updateTask() führen wir die folgenden Schritte aus:
- Besorgen Sie sich die Aufgabe, die aktualisiert werden muss.
- Überprüfen Sie das Element, das das Ereignis ausgelöst hat. Wenn das Element das Attribut
contenteditablehat (d. h. Es ist dasspan-Element), setzen wir den Namen der Aufgabe gleich dem Textinhalt desspan. - Andernfalls (d. h. Es ist das Kontrollkästchen) schalten wir den Status der Aufgabe und das
checked-Attribut um. Außerdem schalten wir dascontenteditable-Attribut der angrenzendenspanum. - Aktualisieren Sie den Wert des
tasks-Schlüssels im lokalen Speicher. - Rufen Sie die Funktion
countTasks()auf.
Hier ist die Syntax für diese Funktion:
1 |
function updateTask(taskId, el) { |
2 |
// 1
|
3 |
const task = tasks.find((task) => task.id === parseInt(taskId)); |
4 |
|
5 |
if (el.hasAttribute("contentEditable")) { |
6 |
// 2
|
7 |
task.name = el.textContent; |
8 |
} else { |
9 |
// 3
|
10 |
const span = el.nextElementSibling.nextElementSibling; |
11 |
task.isCompleted = !task.isCompleted; |
12 |
if (task.isCompleted) { |
13 |
span.removeAttribute("contenteditable"); |
14 |
el.setAttribute("checked", ""); |
15 |
} else { |
16 |
el.removeAttribute("checked"); |
17 |
span.setAttribute("contenteditable", ""); |
18 |
}
|
19 |
}
|
20 |
// 4
|
21 |
localStorage.setItem("tasks", JSON.stringify(tasks)); |
22 |
// 5
|
23 |
countTasks(); |
24 |
}
|
Entfernen Sie eine Aufgabe
Wir können eine Aufgabe über die Schaltfläche "Schließen" entfernen.



Ähnlich wie beim Aktualisierungsvorgang können wir dieser Schaltfläche kein Ereignis direkt zuordnen, da sie sich beim Laden der Seite nicht im DOM befindet.
Dank der Ereignisdelegation fügen wir der übergeordneten Liste ein click-Ereignis hinzu und führen die folgenden Aktionen aus:
- Überprüfen Sie, ob das Element, auf das geklickt wird, die Schaltfläche "Schließen" oder die untergeordnete SVG-Datei ist.
- In diesem Fall ermitteln wir die
iddes übergeordneten Listenelements. - Übergeben Sie diese
idan die FunktionremoveTask().
Hier ist der relevante Code:
1 |
const todoList = document.querySelector(".todo-list"); |
2 |
|
3 |
todoList.addEventListener("click", (e) => { |
4 |
// 1
|
5 |
if ( |
6 |
e.target.classList.contains("remove-task") || |
7 |
e.target.parentElement.classList.contains("remove-task") |
8 |
) { |
9 |
// 2
|
10 |
const taskId = e.target.closest("li").id; |
11 |
// 3
|
12 |
removeTask(taskId); |
13 |
}
|
14 |
});
|
In der Funktion removeTask() führen wir die folgenden Schritte aus:
- Entfernen Sie die zugehörige Aufgabe aus dem
tasks-Array. - Aktualisieren Sie den Wert des
tasks-Schlüssels im lokalen Speicher. - Entfernen Sie das zugehörige Listenelement.
- Rufen Sie die Funktion
countTasks()auf.
Hier ist die Syntax für diese Funktion:
1 |
function removeTask(taskId) { |
2 |
// 1
|
3 |
tasks = tasks.filter((task) => task.id !== parseInt(taskId)); |
4 |
// 2
|
5 |
localStorage.setItem("tasks", JSON.stringify(tasks)); |
6 |
// 3
|
7 |
document.getElementById(taskId).remove(); |
8 |
// 4
|
9 |
countTasks(); |
10 |
}
|
Aufgaben zählen
Wie bereits erwähnt, enthalten viele der oben genannten Funktionen die Funktion countTask().
Seine Aufgabe besteht darin, die Aufgaben auf Änderungen (Hinzufügungen, Aktualisierungen, Löschungen) zu überwachen und den Inhalt der zugehörigen Elemente zu aktualisieren.



Hier ist seine Unterschrift:
1 |
const totalTasks = document.querySelector(".total-tasks span"); |
2 |
const completedTasks = document.querySelector(".completed-tasks span"); |
3 |
const remainingTasks = document.querySelector(".remaining-tasks span"); |
4 |
|
5 |
function countTasks() { |
6 |
totalTasks.textContent = tasks.length; |
7 |
const completedTasksArray = tasks.filter((task) => task.isCompleted === true); |
8 |
completedTasks.textContent = completedTasksArray.length; |
9 |
remainingTasks.textContent = tasks.length - completedTasksArray.length; |
10 |
}
|
Verhindern Sie das Hinzufügen neuer Zeilen
Jedes Mal, wenn ein Benutzer den Namen einer Aufgabe aktualisiert, sollte er keine neuen Zeilen durch Drücken der Eingabetaste erstellen können.



Um diese Funktionalität zu deaktivieren, nutzen wir erneut die Ereignisdelegation und hängen das keydown-Ereignis wie folgt an die Liste an:
1 |
todoList.addEventListener("keydown", function (e) { |
2 |
if (e.keyCode === 13) { |
3 |
e.preventDefault(); |
4 |
}
|
5 |
});
|
Beachten Sie, dass in diesem Szenario nur die span-Elemente dieses Ereignis auslösen können, sodass keine zusätzliche Prüfung wie folgt erforderlich ist:
1 |
if (e.target.hasAttribute("contenteditable") && e.keyCode === 13) { |
2 |
e.preventDefault(); |
3 |
}
|
Daten beim Laden der Seite beibehalten
Wenn wir den Browser schließen und zum Demo-Projekt navigieren, verschwinden unsere Aufgaben.
Aber warten Sie, das ist nicht 100% wahr! Denken Sie daran, dass wir bei jeder Aufgabenmanipulation auch das tasks-Array im lokalen Speicher speichern. Um beispielsweise in Chrome die lokalen Speicherschlüssel und -werte anzuzeigen, klicken Sie auf die Registerkarte Anwendung, erweitern Sie das Menü Lokaler Speicher und klicken Sie schließlich auf eine Domäne, um deren Schlüssel-Wert-Paare anzuzeigen.
In meinem Fall sind hier die Werte für den tasks-Schlüssel:



Um diese Aufgaben anzuzeigen, müssen wir sie zunächst aus dem lokalen Speicher abrufen. Dazu verwenden wir die Methode JSON.parse(), mit der die Zeichenfolgen wieder in JavaScript-Objekte konvertiert werden.
Als Nächstes speichern wir alle Aufgaben im vertrauten tasks-Array. Beachten Sie, dass dieses Array leer ist, wenn sich keine Daten im lokalen Speicher befinden (z. B. beim ersten Besuch der App). Dann müssen wir das Array durchlaufen und für jede Aufgabe die Funktion createTask() aufrufen. Und das ist alles!
Das entsprechende Code-Snippet:
1 |
let tasks = JSON.parse(localStorage.getItem("tasks")) || []; |
2 |
|
3 |
if (localStorage.getItem("tasks")) { |
4 |
tasks.map((task) => { |
5 |
createTask(task); |
6 |
});
|
7 |
}
|
Schlussfolgerung
Puh! Vielen Dank, dass Sie diese lange Reise mitgemacht haben. Hoffentlich haben Sie heute einige neue Kenntnisse gewonnen, die Sie auf Ihre eigenen Projekte anwenden können.
Erinnern wir uns daran, was wir gebaut haben:
Ohne Zweifel ist das Erstellen einer solchen App mit einem JavaScript-Framework möglicherweise stabiler, einfacher und effizienter (das Neulackieren des DOM ist teuer). Wenn Sie jedoch wissen, wie Sie diese Art von Übung mit einfachem JavaScript lösen können, erhalten Sie einen soliden Überblick über die Grundlagen und werden zu einem besseren JavaScript-Entwickler.
Lassen Sie mich vor dem Abschluss zwei Ideen zur Erweiterung dieser Übung vorschlagen:
- Verwenden Sie die HTML-Drag & Drop-API oder eine JavaScript-Bibliothek wie Sortable.js, um die Aufgaben neu zu ordnen.
- Speichern Sie Daten(Aufgaben) in der Cloud anstelle des Browsers. Ersetzen Sie beispielsweise den lokalen Speicher durch eine Echtzeitdatenbank wie Firebase.
Wie immer vielen Dank fürs Lesen!
Weitere Vanilla JavaScript Apps
Wenn Sie lernen möchten, wie Sie kleine Apps mit einfachem JavaScript erstellen, lesen Sie die folgenden Tutorials:







