mirror of
https://github.com/TheTaz25/denis.ergin.git
synced 2025-07-08 07:38:46 +00:00
Start with Web-API's, update page overview
This commit is contained in:
parent
5958201436
commit
0218f9a613
8 changed files with 562 additions and 0 deletions
170
src/components/slides/javascript/09-web-api/files.astro
Normal file
170
src/components/slides/javascript/09-web-api/files.astro
Normal file
|
@ -0,0 +1,170 @@
|
|||
<section>
|
||||
<section>
|
||||
<h2>Files API</h2>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Als wir über Eingabemöglichkeiten in HTML mit dem <code><input /></code> Element betrachtet haben, haben wir auch den <code>type="file"</code> kennen gelernt.</p>
|
||||
<p>Sobald der Nutzer eine Datei ausgewählt hat, können wir im dazugehörigen <em>change-Eventlistener</em> auf diese Datei und deren Inhalt zugreifen. Wir müssen also nicht unbedingt den Inhalt an einen Server senden.</p>
|
||||
<p>Es ist aber auch möglich, mit der normalen DOM-API auf die Dateien zuzugreifen.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Sehen wir uns einmal an, was wir beim <code>change-event</code> so erhalten.</p>
|
||||
<pre class="js"><code data-trim data-line-numbers is:raw>
|
||||
const input = document.getElementById('file-input');
|
||||
|
||||
input.addEventListener('change', onFile, false);
|
||||
|
||||
function onFile (event) {
|
||||
// Alle selektierten Dateien befinden sich im Element in "files"
|
||||
const selected = event.target.files;
|
||||
console.log(selected);
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Das Objekt das wir hier erhalten stammt von der besonderen Klasse <em>FileList</em>. Das Objekt verhält sich im weitesten Sinne wie ein Array. Also ist auch der Zugriff mittels der Array-Syntax auf einzelne Elemente möglich.</p>
|
||||
<p>Sehen wir uns mal den Inhalt genauer an. Innerhalb einer <em>FileList</em> befinden sich <em>File</em> Objekte. Dort befinden sich ein paar Informationen zur ausgewählten Datei.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<pre class="js"><code data-trim data-line-numbers is:raw>
|
||||
function onFile (event) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
console.log(file);
|
||||
}
|
||||
</code></pre>
|
||||
<p>Im Log finden wir folgendes:</p>
|
||||
<pre><code data-trim data-line-numbers is:raw>
|
||||
File {
|
||||
lastModified: 1730637507228,
|
||||
name: "datei.png",
|
||||
size: 2583226,
|
||||
type: "image/png"
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Neben den Allgemeinen Informationen wie Dateiname, Dateigröße oder das letzte Änderungsdatum, bietet uns die darunter liegende Klasse "Blob".</p>
|
||||
<p>Diese Klasse bietet uns ein paar Methoden um den Inhalt aus der Datei zu erhalten. Für einfache Text-Dateien gibt es hierfür die Convenience-Funktion <code>.text()</code>. Diese Funktion ist async, sprich muss mit einem <code>await</code> versehen werden.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Das Ergebnis der Funktion resultiert nach dem <code>await</code> den Textinhalt der Datei.</p>
|
||||
<p>Bei anderen Dateien (z.B. Bilder) fällt ein wenig mehr Arbeit an.</p>
|
||||
<p>Insgesamt ist es in JavaScript nicht notwendig den Inhalt aus einer Textdatei zu extrahieren; Bei einem Versand mit dem Form-Element sorgt der Browser dafür, dass der Inhalt korrekt übertragen wird.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Wollen wir aber den Inhalt der Datei noch in der Web-Ansicht editiert, betrachtet oder sonst in irgendeiner Art und Weise modifizieren, müssen wir - zumindest für Binär-Dateien wie Bildern - noch der Inhalt extrahiert werden.</p>
|
||||
<p>Im Folgenden Beispiel anhand eines Bildes, betrachten wir 2 Möglichkeiten um den Inhalt vor dem Absenden anzuschauen.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Das Bild zur Vorschau darstellen</p>
|
||||
<pre class="js"><code data-trim data-line-numbers="2-5|7,14|8|10|11-13" is:raw>
|
||||
function onFile(event) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
const previewElement = document
|
||||
.getElementById('preview');
|
||||
|
||||
if (file) {
|
||||
const url = URL.createObjectURL(file);
|
||||
|
||||
preview.src = url;
|
||||
preview.onload = function () {
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Was passierte:</p>
|
||||
<ol>
|
||||
<li>Wir entnehmen die "hochgeladene" Datei und besorgen uns das Element zur Preview</li>
|
||||
<li>Um einen "Abbruch" abzuhandeln prüfen wir ob wirklich <code>File</code> vorhanden ist</li>
|
||||
<li>Mit <code>URL.createObjectURL(file);</code> erstellen wir einen <em>internen</em> Browserlink</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<ol start="4">
|
||||
<li>Die resultierende URL können wir dem Preview-Element als <code>src</code> anhängen</li>
|
||||
<li>Sobald das Bild geladen wurde, können wir mit der <code>onload</code> Funktion darauf reagieren.</li>
|
||||
<li>Um den Speicher zu befreien soll man <code>URL.revokeObjectURL(url);</code> aufrufen.</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Variante 2: Den eigentlichen Datei-Inhalt "parsen" und die Binär-Daten zur Preview verwenden.</p>
|
||||
<p>Hier ist etwas "mehr" Arbeit zu verrichten. Vorteil mit dieser Art und Weise ist aber, dass wir den Datei-inhalt direkt verfügbar haben und modifizieren können (Zumindest mit dem konkreten Wissen wie man das macht).</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<pre class="js"><code data-trim data-line-numbers="5-7|10|11|12" is:raw>
|
||||
function onChange(event) {
|
||||
const file = event.target.files[0];
|
||||
const preview = document.getElementById('preview');
|
||||
|
||||
function parseImage(e) {
|
||||
// ...
|
||||
}
|
||||
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = parseImage;
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<ol>
|
||||
<li>Wir legen eine Funktion parseImage an, was die genau macht implementieren wir gleich</li>
|
||||
<li>Wir legen eine neue <code>FileReader</code>-Instanz an</li>
|
||||
<li>Der <code>reader</code> erwartet eine Funktion für ein <code>onload</code> Event, wir weisen ihr die <code>parseImage</code>-Funktion zu</li>
|
||||
<li>Zuletzt rufen wir die Funktion <code>readAsArrayBuffer</code> der FileReader-Instanz auf. Bei Erfolg ruft diese die Funktion <code>parseImage</code> auf.</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<pre class="js"><code data-trim data-line-numbers="2-3|5-7|9|10|12" is:raw>
|
||||
function parseImage(e) {
|
||||
const arrayBuffer = e.target.result;
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
||||
const base64 = btoa(uint8Array.reduce((data, byte) =>
|
||||
data + String,fromCharCode(byte), ''
|
||||
);
|
||||
|
||||
const mimteType = file.type || 'image/jpeg';
|
||||
const dataUrl = `data:${mimeType};base64,${base64}`;
|
||||
|
||||
preview.src = dataUrl;
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<ol>
|
||||
<li>Das Resultat der Funktion <code>readAsArrayBuffer</code> erhalten wir in unserer Funktion im Event. Dieses nehmen wir und konvertieren es in ein Uint8Array</li>
|
||||
<li>In den Zeilen 5 bis 7 konvertieren wir die Informationen in Characters und wandeln diese in einen Base-64 kodierten String um</li>
|
||||
<li>Darauffolgend entnehmen wir den Bild-Typen (JPEG)</li>
|
||||
<li>Wir fassen alle gesamelten Informationen in einen korrekt definierten String zur Bild-Darstellung zusammen</li>
|
||||
<li>Zu guter letzt verwenden wir die Bildinformationen im <code>src</code>-Attribut des <code>img</code>-Elementes</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Aus dieser Position heraus haben wir alle Bildinformationen vorhanden und können mit diesen Arbeiten / modifizieren.</p>
|
||||
<p>Wie wir diese Informationen modifizieren um das Bild zu modifizieren ist außerhalb des Scopes der Vorlesung.</p>
|
||||
</section>
|
||||
</section>
|
242
src/components/slides/javascript/09-web-api/history.astro
Normal file
242
src/components/slides/javascript/09-web-api/history.astro
Normal file
|
@ -0,0 +1,242 @@
|
|||
<section>
|
||||
<section>
|
||||
<h2>History API</h2>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Mit der History API können wir per JavaScript mit der Browser-History
|
||||
interagieren.
|
||||
</p>
|
||||
<p>
|
||||
Während sich der User durch verschiedene Dokumente klickt, wird jeder
|
||||
Seitenbesuch in die History gelegt.
|
||||
</p>
|
||||
<p>
|
||||
Durch die Buttons neben der URL-Bar interagiert der Nutzer mit der
|
||||
Browser-History und springt darin vor und zurück.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Das <code>history</code> Objekt ist im Browser im globalen Scope verfügbar.
|
||||
</p>
|
||||
<p>
|
||||
Es bietet einige Funktionen um zu anderen Seiten zu navigieren und die
|
||||
bisherige history zu modifizieren.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>history.back()</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Mit dieser Funktion springen wir in der Browser-History einen Eintrag aus
|
||||
dem aktuellen Tab zurück.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>history.forward()</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Mit dieser Funktion springt der Browser in der History um einen Eintrag
|
||||
"nach vorne", sofern in der History nach vorne ein Eintrag vorhanden ist.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>history.go(<i>delta</i>)</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Mittels go können wir mehrere Einträge in der Browser-History
|
||||
überspringen.
|
||||
</p>
|
||||
<p>
|
||||
Mit dem <i>delta</i> Parameter können wir die Anzahl der Einträge bestimmen.
|
||||
(Es sind auch negative Zahlen möglich)
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Die Funktionen <code>back, forward & go</code> sind <strong
|
||||
>asynchron</strong
|
||||
> und lösen <code>popstate</code> Events aus.
|
||||
</p>
|
||||
<p>
|
||||
Dieser Umstand ist wichtig, wenn wir sogenannte <em
|
||||
>Single State Applications</em
|
||||
> entwickeln. Wir müssen dann in der Lage sein eine Navigation abzubrechen
|
||||
und den Zustand in der UI zu aktualisieren.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Für den normalen Webentwickler ist dieser Umstand "weniger wichtig",
|
||||
moderne Bibliotheken und Frameworks kapseln die Logik komplett ab.
|
||||
</p>
|
||||
<p>
|
||||
Aber sehen wir uns das <code>popstate</code> Event kurz etwas näher an:
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<pre
|
||||
class="js"><code data-trim data-line-numbers is:raw>
|
||||
// Das Event kommt am window an
|
||||
window.addEventListener('popstate', (event) => {
|
||||
console.log(`location: ${document.location}`);
|
||||
// in event.state stehen ggf. weitere infos
|
||||
console.log(`state: ${JSON.stringify(event.state)}`);
|
||||
})
|
||||
</code></pre>
|
||||
<p>
|
||||
Dieses Event ist für den Umstand wichtig, wenn der Nutzer mittels der
|
||||
Browser-Navigation die Seite ändert.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Für den Fall das der User mit der Seite interagiert und eine Navigation
|
||||
auslöst, können wir einfach das Event abfangen.
|
||||
</p>
|
||||
<pre
|
||||
class="js"><code data-trim data-line-numbers is:raw>
|
||||
// aTag ist nur ein generisches a-tag auf das ein User klickt
|
||||
aTag.addEventListener('click', (event) => {
|
||||
// Unterbricht die Event-Kette
|
||||
// Verhindert dass der Browser die Seite wechselt
|
||||
event.preventDefault();
|
||||
|
||||
// Ab hier können wir die UI aktualisieren
|
||||
});
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>history.pushState(<em>state, unused, url</em>)</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Mit <code>pushState</code> fügen wir einen neuen Eintrag in der Browser-History
|
||||
hinzu.
|
||||
</p>
|
||||
<p>
|
||||
Der Browser wird nicht automatisch die neue URL laden, sondern dann wenn
|
||||
es notwendig ist (z.B. wenn der Browser neu startet.). Wir können aber die
|
||||
neue "gepushte" URL mit <code>history.go()</code> aufrufen.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Wir können nur URL's auf der gleichen Origin angeben, ansonsten wirft die
|
||||
Funktion einen Error.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>history.replaceState(<em>state, unused, url</em>)</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Ähnlich zu <code>pushState</code>, modifiziiert diese Funktion die
|
||||
Browser-History.
|
||||
</p>
|
||||
<p>
|
||||
Anders aber ist aber, dass der aktuelle (oberste) History-Eintrag von
|
||||
dieser Funktion überschrieben wird.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Besonders nützlich ist diese Funktionalität, wenn der User auf einer Seite
|
||||
die URL mehrmals durch Aktionen ändert, die aber keinen Reload der Seite
|
||||
triggern.
|
||||
</p>
|
||||
<p>Gängige Beispiele hierfür sind:</p>
|
||||
<ul>
|
||||
<li>Filtern von Suchergebnissen</li>
|
||||
<li>Tab-Navigation innerhalb einer Seite</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Die URL-Klasse</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Die URL-Klasse ist hilfreiche um eine Strukturierte URL zu generieren.
|
||||
</p>
|
||||
<p>
|
||||
Sie bietet viele Funktionen um eine URL durch verschiedene Teile zu
|
||||
erweitern (Query-Parameter zum Beispiel)
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Das URL-Objekt lässt sich folgendermaßen aus dem Konstruktor erstellen
|
||||
</p>
|
||||
<pre
|
||||
class="js"><code data-trim data-line-numbers is:raw>
|
||||
const baseUrl = "https://www.denis-ergin.de";
|
||||
|
||||
// Erstellt eine URL zu
|
||||
// "https://www.denis-ergin.de/slides/javascript/00-intro"
|
||||
const url = new URL("/slides/javascript/00-intro", baseUrl);
|
||||
|
||||
/**
|
||||
* new URL(Pfad, BaseUrl);
|
||||
*/
|
||||
</code></pre>
|
||||
<p>Diese URL kann z.B. auch für die History-API verwendet werden.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Das resultierende URL Objekt hat nun Möglichkeiten auf bestimmte Teile
|
||||
zuzugreifen und zu modifieren, sowie die komplette URL zu generieren.
|
||||
</p>
|
||||
<pre
|
||||
class="js"><code data-trim data-line-numbers is:raw>
|
||||
const baseUrl = "https://www.denis-ergin.de";
|
||||
const url = new URL("/slides/javascript/00-intro", baseUrl);
|
||||
|
||||
console.log(
|
||||
url.host, // Hostname + ggf Port
|
||||
url.hostname, // z.B. google
|
||||
url.origin, // scheme + domain + port
|
||||
url.pathname, // Pfad ("/...")
|
||||
url.search, // Der Query-String (kommt nach dem "?")
|
||||
url.protocol, // Protokoll (":" inbegriffen)
|
||||
);
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Wenn wir URL's modifizieren oder generieren müssen, sollten wir die
|
||||
gegebene URL-Klasse verwenden, anstatt einen selbst-gebauten String zu
|
||||
kreiieren.
|
||||
</p>
|
||||
<p>
|
||||
Die URL-Klasse hat einen entscheidenden Vorteil: Potenziell "kritische"
|
||||
Zeichen werden von der Klasse korrekt behandelt.
|
||||
</p>
|
||||
</section>
|
||||
</section>
|
21
src/components/slides/javascript/09-web-api/index.astro
Normal file
21
src/components/slides/javascript/09-web-api/index.astro
Normal file
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
import Title from "./title.astro";
|
||||
import HistoryApi from "./history.astro";
|
||||
import FilesApi from './files.astro';
|
||||
import IntersectionApi from './intersection.astro';
|
||||
// import ProxyApi from './proxy.astro';
|
||||
// import SelectionApi from './selection.astro';
|
||||
// import ServiceWorker from './service-worker.astro';
|
||||
// import SpeechApi from './speech.astro';
|
||||
// import AnimationApi from './animations.astro';
|
||||
import StorageApi from "./storage.astro";
|
||||
---
|
||||
|
||||
<div class="slides">
|
||||
<Title />
|
||||
<HistoryApi />
|
||||
<StorageApi />
|
||||
<FilesApi />
|
||||
<IntersectionApi />
|
||||
</div>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<section>
|
||||
<section>
|
||||
<h2>Intersection-API</h2>
|
||||
</section>
|
||||
</section>
|
90
src/components/slides/javascript/09-web-api/storage.astro
Normal file
90
src/components/slides/javascript/09-web-api/storage.astro
Normal file
|
@ -0,0 +1,90 @@
|
|||
<section>
|
||||
<section>
|
||||
<h2>Storage API</h2>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Mit der Storage-API haben wir eine einfache aber wirkungsvolle Art, um Informationen zu speichern und später wieder abzufragen.
|
||||
</p>
|
||||
<p>
|
||||
Dafür stehen uns 2 "dedizierte" Speicher-Orte zur Verfügung: Der sessionStorage und der localStorage.
|
||||
</p>
|
||||
<p>
|
||||
Beide haben die gleichen Funktionen um Inhalte zu speichern, nur die "Speicherdauer" variiert.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Während wir im <code>localStorage</code> Inhalte auf "unbestimmte" Zeit speichern können, werden Daten im <code>sessionStorage</code> gelöscht, wenn der letzte Tab der Website geschlossen wird, auf dem die Daten gespeichert wurden.
|
||||
</p>
|
||||
<p>
|
||||
Da beide Arten die gleiche API besitzen, betrachten wir nur die langfristige Variante zum Speichern von Daten.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Daten speichern</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Daten im <em>storage</em> werden anhand eines <strong>Key-Value-Paares</strong> gespeichert. Das lässt uns mit der Gefahr im Fall der Fälle ungewollt Daten zu überschreiben. Einmal überschrieben können wir auch nicht mehr auf die Daten davor zugreifen.
|
||||
</p>
|
||||
<p>
|
||||
Wichtig ist zu beachten, dass nur Strings gespeichert werden können. Wollen wir also JSON-Formattierte Daten speichern wollen, müssen wir diese vorher mit <code>JSON.stringify()</code> zu einem String umwandeln.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<pre
|
||||
class="js"><code data-trim data-line-numbers is:raw>
|
||||
const toSave = "Hallo TINF24BX!";
|
||||
const key = 'greeting';
|
||||
|
||||
localStorage.setItem(key, toSave);
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Daten abfragen</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>
|
||||
Wir können die Daten aus dem storage mithilfe des Key's auch wieder abholen:
|
||||
</p>
|
||||
<pre class="js"><code data-trim data-line-numers>
|
||||
const data = localStorage.getItem('key');
|
||||
|
||||
console.log(data);
|
||||
</code></pre>
|
||||
<p>
|
||||
Auch hier gilt wieder: Wenn wir strukturierte Dateien im JSON-Format abgespeichert haben, so müssen die Daten auch wieder mit <code>JSON.parse()</code> umformattiert werden um diese zu nutzen.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3>Daten löschen</h3>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Sollten wir Daten aus dem Storage löschen wollen, geht das ganz einfach mit dem <em>key</em> und der Funktion <code>localStorage.removeItem(<em>key</em>)</code>.</p>
|
||||
<pre class="js"><code data-trim data-line-numbers is:raw>
|
||||
const key = 'greeting';
|
||||
|
||||
let data = localStorage.getItem(key);
|
||||
console.log(data); // Wir erwarten hier etwas...
|
||||
|
||||
localStorage.removeItem(key);
|
||||
data = localStorage.getItem(key);
|
||||
|
||||
console.log(data); // undefined...
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Wenn wir den gesamten Storage löschen möchten, gibt es die Funktion <code>localStorage.clear()</code>. Daraufhin werden alle gespeicherten <em>Key-Value</em>-Paare gelöscht.</p>
|
||||
</section>
|
||||
</section>
|
3
src/components/slides/javascript/09-web-api/title.astro
Normal file
3
src/components/slides/javascript/09-web-api/title.astro
Normal file
|
@ -0,0 +1,3 @@
|
|||
<section>
|
||||
<h1>JavaScript Web-API's</h1>
|
||||
</section>
|
Loading…
Add table
Add a link
Reference in a new issue