branch-coexist: 3 neue decks 223015b-2026 / 223015c-2026 / dhbw-2026 daneben main

per user-request einen branch der main-content UND rewrite-content trägt — saubere separierung statt symlink/merge-conflict.

struktur:
- slides/<course>/ → main-content restored, eigene assets (kein new-demo-leak)
- slides/<course>-2026/ → rewrite-content, eigene assets (komplett kopiert + new demos)

Makefile: COURSES += 223015b-2026 223015c-2026 dhbw-2026 mit eigenen NAME/KAPITEL/DEPLOY/KLAUSUR-konfig. Klausur für b+c=1, dhbw=leer. Deploy-paths /hdm/223015b-2026 etc.

make build durchlaufen für alle 6 decks, 0 fehler.

dedup: 223015c+dhbw assets identisch in beiden ordnern (kein neu-demos auf b ergänzt). 223015b 86 → 120 files in -2026 (= +34 neue eroeffner/usb-c-drei-achsen/container-vs-codec/etc).
This commit is contained in:
libretech committed 2026-05-14 21:54:15 +02:00
1 parent 6209f9f3a0
commit 351e3dfc23
467 files changed
+32391 -4701

No files matched your search

@@ -0,0 +1,901 @@
---
marp: true
theme: gaia
paginate: true
backgroundColor: #fff
header: "Grundlagen IT- und Internettechnik (223015c)"
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
title: "Kapitel 3: Interaktivität & JavaScript"
---
<style>
:root {
--color-foreground: #1a1a2e;
--color-highlight: #d63384;
--color-dimmed: #4a4a6a;
}
section.invert { --color-foreground: #fff; }
section { font-size: 1.7rem; }
h1 { color: #a02060; }
section.invert h1 { color: #fff; }
h2 { color: #1f2937; }
pre {
background: #0f0f23;
color: #d63384;
border-radius: 8px;
border-left: 3px solid #d63384;
}
pre code { background: transparent; color: inherit; }
code {
background: #0f0f23;
padding: 0.15em 0.4em;
border-radius: 4px;
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}
section code:not(.hljs) { color: #d63384 !important; }
section code.hljs { color: #f8f8f8 !important; }
a { color: var(--color-highlight); }
section.aufgabe { background: #fce4ec !important; }
section.aufgabe footer { display: none; }
section.erklaerung { font-size: 1.1rem; }
section.erklaerung h1 { font-size: 1.5rem; color: #a02060; margin-bottom: 0.3rem; }
</style>
<!-- _class: lead -->
# Kapitel 3
## Interaktivität & JavaScript
<!--
Eine Stunde, eine Frage: *Was passiert, wenn HTML + CSS da sind und nichts reagiert?*
JavaScript (JS) macht Webseiten interaktiv:
- DOM manipulieren (Elemente ändern, hinzufügen, entfernen)
- Auf Events reagieren (Klick, Tastendruck, Scroll)
- Daten holen (fetch) + speichern (localStorage)
- Animationen, dynamische UI, SPA-Frameworks
Per Klausur-Themen-Vorschlag: JavaScript ist nicht klausurrelevant. Lernziele auf Verstehen-Niveau (Code-Lesen, nicht Code-Schreiben).
-->
---
<!-- _class: lead -->
# „Statisch ist langweilig"
<!--
Hook: eine reine HTML+CSS-Seite reagiert auf nichts. Klick auf Button → nichts passiert (außer Form-Submit).
JS bringt das Reagieren rein. Daher der Name „Interaktivität".
Beispiele aus dem Alltag:
- Dropdown-Menü, das aufklappt
- Dark-Mode-Toggle
- „Mehr laden"-Button ohne Page-Reload
- Live-Validierung in Formularen
- Maps, die zoomen
- Spotify-Player, der weitermacht beim Wechseln der Seite
-->
---
# Was kann JavaScript?
| Kann | Beispiel |
|------|----------|
| DOM ändern | Element-Text, -Klasse, -Inhalt manipulieren |
| Events behandeln | Klick, Tastendruck, Scroll, Submit |
| Daten holen | `fetch()` API-Anfragen |
| Daten lokal speichern | `localStorage`, `sessionStorage` |
| Animationen | `requestAnimationFrame`, CSS-Animationen triggern |
| Web-APIs nutzen | Geolocation, Camera, Audio, Notification |
**Aus Sicherheitsgründen NICHT:** willkürlich Dateien auf der Platte lesen/schreiben.
<!--
JavaScript läuft im Browser-Sandkasten. Es darf:
- alles am DOM ändern
- Daten an Server schicken (mit CORS-Beschränkungen)
- LocalStorage für ~5-10 MB nutzen
- Mit User-Erlaubnis: GPS, Kamera, Mikrofon, Push-Notifications
JS darf NICHT (ohne User-Aktion):
- Beliebige Dateien lesen oder schreiben (FileSystem-Access nur mit User-Picker)
- Auf andere Tabs / Fenster zugreifen (Same-Origin-Policy)
- Direkt zu beliebigen Servern verbinden (CORS-Schutz)
Außerhalb des Browsers: Node.js erlaubt JS, alles zu tun was eine Programmiersprache normal kann (Files, Netzwerk, Kindprozesse). Davon später (in DHBW-Modul).
-->
---
# JavaScript-Timeline
| Jahr | Was |
|------|-----|
| **1995** | Brendan Eich entwickelt JS in 10 Tagen für Netscape |
| 1997 | ECMAScript-1 standardisiert (offizieller Name) |
| 2009 | **Node.js** — JS auch außerhalb des Browsers |
| **2015** | ES6 (große Erneuerung: `let`, `const`, arrow functions, classes, modules) |
| 2017+ | jährliche Updates (ES2017, ES2018, …) |
| heute | TypeScript als statisch-getypter Aufsatz |
JS ist die **am weitesten verbreitete** Programmiersprache der Welt.
<!--
Brendan Eich bekam 10 Tage um JavaScript zu entwickeln — daher viele frühe Quirks (`null` ist ein object, `0 == "0"` ist true). Diese Quirks bleiben aus Kompatibilitätsgründen.
Node.js (2009) hat alles verändert: JS ist nicht mehr nur Browser-Spielzeug, sondern serverseitig nutzbar. Heute laufen viele große Websites auf Node-Backend (Netflix, LinkedIn, Walmart).
ES6 (2015) brachte JS auf moderne Sprachen-Niveau:
- `let` und `const` statt `var`
- Arrow functions: `(x) => x * 2`
- Classes (Syntax-Sugar für Prototyp-Vererbung)
- Modules: import/export
Seitdem: jährliche Updates mit kleineren Features.
-->
---
# JavaScript einbinden
```html
<!-- External (best practice) -->
<script src="./app.js"></script>
<!-- Inline (für kleine Snippets) -->
<script>
console.log('Hallo Welt');
</script>
<!-- Modern: als Modul -->
<script type="module" src="./main.js"></script>
```
**Modern:** als ES-Modul mit `type="module"`. Erlaubt `import` / `export`.
<!--
Drei Wege, JS in HTML einzubinden:
1. External via `<script src="...">` — Best Practice für nicht-triviale Apps
2. Inline mit `<script>...</script>` — für ganz kleine Snippets, ok
3. ES-Modul mit `type="module"` — für moderne Apps mit import/export
Wichtig: Script-Position
- `<script>` im `<head>` ohne Defer/Async: blockiert das Rendern
- `<script defer>` im head: parallel laden, vor DOMContentLoaded ausführen
- `<script async>`: parallel laden, sofort ausführen (gefährlich für Reihenfolge)
- `<script>` am Ende des `<body>`: erst nach HTML-Parsing
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-console.png)
<!--
Die Browser-Konsole ist die wichtigste JS-Spielwiese für Anfänger.
DevTools öffnen (F12), Tab „Console":
- `console.log('Hallo')` → Hallo
- `1 + 1` → 2
- `let x = 10` → undefined, dann `x` → 10
- `document.title` → aktueller Tab-Titel
- `document.body.style.background = 'pink'` → Hintergrund wird pink
Studis können in der Konsole alles erst mal ausprobieren, bevor sie eine richtige .js-Datei schreiben.
-->
---
# Variablen — Daten speichern
```javascript
let name = "Ada"; // veränderlich
const PI = 3.14159; // konstant
var alt = "vermeiden"; // pre-ES6, hat skopen-bugs
// Verändern:
name = "Grace"; // OK
PI = 3.0; // FEHLER: const kann nicht überschrieben werden
```
**Faustregel:** `const` als Default. Nur `let`, wenn man umzuweisen plant. Niemals `var`.
<!--
Variable-Deklaration:
- `let`: Block-skopisch, veränderlich
- `const`: Block-skopisch, nicht-überschreibbar
- `var`: function-skopisch, hat historische Bugs — vermeiden
`const` heißt nicht „unveränderlich" — bei Objekten/Arrays kann der Inhalt verändert werden, nur die Referenz nicht.
```javascript
const list = [1, 2, 3];
list.push(4); // OK — Array selbst ist mutiert
list = []; // FEHLER — Referenz kann nicht überschrieben werden
```
-->
---
# Datentypen
```javascript
let text = "Hallo"; // string
let zahl = 42; // number
let ist_an = true; // boolean
let nichts = null; // null
let nicht_gesetzt; // undefined
let liste = [1, 2, 3]; // array
let objekt = { x: 1 }; // object
typeof text // "string"
typeof liste // "object" (auch arrays sind objects)
```
**6 Grund-Typen** + objects/arrays.
<!--
JavaScript ist dynamisch typisiert: eine Variable kann verschiedene Typen halten.
`typeof` zeigt den Typ. Arrays und Objects sind beide „object" — historische Quirks.
Modern: TypeScript fügt statische Typen drüber:
```typescript
let zahl: number = 42;
let text: string = "Hallo";
```
Das ist ein Aufsatz, der zu JavaScript kompiliert wird.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-arrays.png)
<!--
Arrays = geordnete Listen.
```javascript
let früchte = ["Apfel", "Banane", "Kirsche"];
früchte[0] // "Apfel"
früchte.length // 3
früchte.push("Datte") // hängt an
früchte.includes("Banane") // true
früchte.indexOf("Kirsche") // 2
// Array-Methoden:
früchte.map(f => f.toUpperCase()) // ["APFEL", ...]
früchte.filter(f => f.length > 5) // ["Banane", "Kirsche"]
früchte.forEach(f => console.log(f))
```
Alles 0-indiziert.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-objects.png)
<!--
Objekte = Sammlung von Key-Value-Paaren.
```javascript
let person = {
name: "Ada",
alt: 56,
hobbies: ["Mathe", "Schach"]
};
person.name // "Ada"
person["name"] // "Ada" (gleich wie oben)
person.alt = 57 // ändern
// Schlüssel:
Object.keys(person) // ["name", "alt", "hobbies"]
```
JSON ist Objekt-Notation.
-->
---
# Funktionen
```javascript
// Function declaration
function gruessen(name) {
return "Hallo " + name;
}
// Arrow function (modern, kompakt)
const gruessen = (name) => "Hallo " + name;
// Mit mehreren Zeilen
const summe = (a, b) => {
const result = a + b;
return result;
};
gruessen("Ada") // "Hallo Ada"
summe(3, 4) // 7
```
<!--
Funktionen sind in JS „first-class" — können als Variable, als Argument, als Rückgabe-Wert verwendet werden.
Arrow Functions sind die moderne Form (ES6+):
- Kürzer
- Kein eigener `this`-Kontext
- Implizites Return bei One-Liner
Best Practice: arrow functions als default, function declaration wenn man hoisting braucht.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-loops.png)
<!--
Schleifen — Wiederholungen.
```javascript
// for-Schleife (klassisch)
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4
}
// for...of (über Array)
for (const frucht of ["A", "B", "C"]) {
console.log(frucht);
}
// forEach (Array-Methode)
[1, 2, 3].forEach(n => console.log(n));
// map (transformieren)
[1, 2, 3].map(n => n * 2); // [2, 4, 6]
// filter (auswählen)
[1, 2, 3, 4].filter(n => n > 2); // [3, 4]
```
Modern: bevorzuge map/filter/forEach über klassische for-Loops.
-->
---
# Kontrollstrukturen
```javascript
// if / else
if (age >= 18) {
console.log("erwachsen");
} else if (age >= 14) {
console.log("jugendlich");
} else {
console.log("kind");
}
// Ternärer Operator (Kurzform)
const status = age >= 18 ? "erwachsen" : "kind";
// switch (mehrere Werte)
switch (browser) {
case "Chrome": return "Blink";
case "Safari": return "WebKit";
case "Firefox": return "Gecko";
default: return "unknown";
}
```
<!--
Bedingungen mit if/else if/else — wie in vielen Sprachen.
Ternärer Operator ist ein Kurzschluss für einfache if/else: `condition ? a : b`.
switch für viele Werte, oft mit return statt break. Aber: modern oft durch Map oder Object-Lookup ersetzt:
```javascript
const engine = { Chrome: "Blink", Safari: "WebKit" }[browser];
```
-->
---
<!-- _class: lead -->
# Das DOM
## HTML im Speicher des Browsers
<!--
Pivot. Bis hier war JS allgemeine Programmierung. Jetzt: JS im Web-Kontext.
DOM = Document Object Model. Browser bauen aus HTML einen JavaScript-zugreifbaren Baum. JS kann diesen Baum manipulieren.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/dom-tree.png)
<!--
DOM als Baum-Struktur.
Jedes HTML-Element wird zu einem JS-Object. Diese Objects sind verbunden:
- parent: das Eltern-Element
- children: die Kind-Elemente
- nextSibling, previousSibling: die Nachbarn
Wenn JS den DOM ändert, ändert sich SOFORT die Anzeige.
Wichtig: JS kann nicht das HTML auf der Festplatte ändern — nur das DOM IM BROWSER. Wenn die Seite neu geladen wird, ist alles weg.
-->
---
# Elemente finden
```javascript
// EIN Element (erstes match)
const heading = document.querySelector('h1');
const btn = document.querySelector('#submit-button');
const card = document.querySelector('.card');
// MEHRERE Elemente (NodeList)
const allButtons = document.querySelectorAll('button');
const allCards = document.querySelectorAll('.card');
// Iterieren
allButtons.forEach(btn => console.log(btn.textContent));
```
`querySelector(...)` nimmt **denselben Selektor wie CSS.**
<!--
querySelector + querySelectorAll sind die modernen Wege, Elemente im DOM zu finden.
CSS-Selektoren wiederverwendbar:
- `'h1'` — alle h1
- `'#header'` — Element mit id
- `'.card'` — Elemente mit class
- `'nav > a'` — direkte Kinder
- `'input[type="email"]'` — Attribut-Selektor
Alternative ältere Methoden (querySelector ersetzt sie alle):
- `getElementById('header')`
- `getElementsByClassName('card')`
- `getElementsByTagName('h1')`
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-manipulate.png)
<!--
Elemente manipulieren — drei Hauptzugriffe:
```javascript
const el = document.querySelector('.greeting');
// Text-Inhalt
el.textContent = 'Hallo Welt';
// HTML-Inhalt (gefährlich — XSS-Risiko bei User-Input!)
el.innerHTML = '<strong>Achtung!</strong>';
// Attribute
el.setAttribute('href', 'https://librete.ch');
el.getAttribute('class');
// Klassen
el.classList.add('active');
el.classList.remove('hidden');
el.classList.toggle('open');
```
innerHTML ist mächtig, aber bei User-Input gefährlich — XSS-Angriffe möglich. Lieber textContent + createElement.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-create.png)
<!--
Elemente neu erzeugen:
```javascript
const newP = document.createElement('p');
newP.textContent = 'Frisch gemacht';
newP.classList.add('notice');
document.body.appendChild(newP);
// Elemente entfernen
const old = document.querySelector('.old-stuff');
old.remove();
```
Verwendung: To-Do-Items dynamisch hinzufügen, Chat-Nachrichten anzeigen, Modal öffnen.
-->
---
<!-- _class: lead -->
# Events
## Auf User-Aktionen reagieren
<!--
Events = Ereignisse, die im Browser passieren:
- click, dblclick
- input, change (Form-Elemente)
- submit (Form)
- keydown, keyup
- scroll, resize
- load, DOMContentLoaded
JS kann auf Events „lauschen" und reagieren.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-event-listener.png)
<!--
Event-Listener: callback function wird ausgeführt, wenn Event passiert.
```javascript
const btn = document.querySelector('#myBtn');
btn.addEventListener('click', () => {
console.log('Klick!');
btn.textContent = 'Geklickt';
});
// Mit Event-Objekt
btn.addEventListener('click', (event) => {
console.log(event.target); // welches Element
console.log(event.clientX); // Maus-X-Koordinate
});
// Mehrere Listener auf einem Element möglich
btn.addEventListener('click', handler1);
btn.addEventListener('click', handler2);
```
Modern: addEventListener statt onclick-Attribut.
-->
---
# Häufige Events
| Event | Wo | Wann |
|-------|----|----|
| `click` | jedes Element | Maus-Klick |
| `input` | input, textarea, select | bei jedem Tastendruck |
| `change` | input, select | wenn Wert verändert (bei blur) |
| `submit` | form | wenn Form abgeschickt wird |
| `keydown` | document, input | beim Tastendruck |
| `scroll` | window, scrollbare Elemente | beim Scrollen |
| `load` | window | wenn Seite + Resources geladen |
| `DOMContentLoaded` | document | wenn DOM bereit (vor Bildern) |
<!--
Pro Event-Typ andere Anwendung:
- input vs change: input feuert bei jedem Tastendruck, change erst wenn der Cursor das Feld verlässt
- submit auf form: erlaubt preventDefault um Standard-Verhalten zu unterbinden
- load: alles geladen (Bilder, CSS) — oft zu spät für JS
- DOMContentLoaded: DOM ready — best practice, JS hier starten
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-preventdefault.png)
<!--
preventDefault: verhindert die Standard-Reaktion.
```javascript
// Form ohne page-reload submitten
form.addEventListener('submit', (e) => {
e.preventDefault(); // verhindert Standard-Reload
// stattdessen: fetch + JSON
});
// Link, der nicht navigieren soll
link.addEventListener('click', (e) => {
e.preventDefault();
// stattdessen: Modal öffnen
});
```
Wichtig für moderne Single-Page-Apps — Navigation wird komplett von JS gesteuert.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-darkmode.png)
<!--
Dark-Mode-Toggle — Klassiker.
```javascript
const toggle = document.querySelector('#darkmode-toggle');
const body = document.body;
toggle.addEventListener('click', () => {
body.classList.toggle('dark-mode');
});
```
CSS:
```css
body.dark-mode {
background: #1a1a2e;
color: #fff;
}
```
In ~10 Zeilen Code + ein bisschen CSS. Erste „echte" interaktive App für Anfänger.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-todo.png)
<!--
To-Do-Liste — der „Hello World" der Web-Apps.
```javascript
const form = document.querySelector('#todo-form');
const input = document.querySelector('#todo-input');
const list = document.querySelector('#todo-list');
form.addEventListener('submit', (e) => {
e.preventDefault();
const text = input.value.trim();
if (!text) return;
const li = document.createElement('li');
li.textContent = text;
list.appendChild(li);
input.value = '';
});
```
Konzepte zusammen:
- Form-Submit + preventDefault
- Element erzeugen (createElement)
- Element anhängen (appendChild)
- Form zurücksetzen
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-fetch.png)
<!--
fetch — Daten holen.
```javascript
fetch('https://api.github.com/users/torvalds')
.then(response => response.json())
.then(data => {
console.log(data.name); // "Linus Torvalds"
console.log(data.public_repos);
})
.catch(error => console.error(error));
// Mit async/await (moderne syntax)
async function ladeUser() {
const res = await fetch('https://api.github.com/users/torvalds');
const data = await res.json();
return data;
}
```
Modern: async/await statt then-Chains.
-->
---
<!-- _header: '' -->
<!-- _footer: '' -->
![bg fit](./assets/demos/js-localstorage.png)
<!--
localStorage — Daten persistent speichern (im Browser).
```javascript
// Speichern (nur Strings möglich)
localStorage.setItem('username', 'Ada');
// Laden
const name = localStorage.getItem('username');
// Object speichern: erst JSON
const settings = { darkmode: true, lang: 'de' };
localStorage.setItem('settings', JSON.stringify(settings));
// Laden: JSON parsen
const saved = JSON.parse(localStorage.getItem('settings'));
// Löschen
localStorage.removeItem('username');
localStorage.clear(); // alles weg
```
5-10 MB pro Origin. Bleibt zwischen Sessions. Nicht für sensible Daten (nicht verschlüsselt).
-->
---
<!-- _class: lead -->
# Frameworks
## Wann braucht man die?
<!--
Frameworks sind „voll-tooled" Abstraktionen über die DOM-API.
Wenn der Code mehr als ~500 Zeilen hat, wird vanilla DOM-Manipulation unübersichtlich. Frameworks helfen mit:
- Komponentenmodell
- Reactive State (Daten ändert sich, UI passt automatisch an)
- Routing
- Tools (Build, Linter, Tests)
-->
---
# React · Vue · Angular · Svelte
| Framework | Typ | Stärke |
|-----------|-----|--------|
| **React** | Library (mit Ökosystem) | dominierend, große Community |
| **Vue** | Framework | sanfter Einstieg, gute Doku |
| **Angular** | Framework | „Enterprise"-Setup, Google |
| **Svelte** | Compiler | kein Virtual DOM, kleine Bundle |
| **Astro** | Hybrid | Static-First, Multi-Framework |
Alle: **Komponenten** als Konzept. **State** verändert sich → UI re-rendert.
<!--
Übersicht ohne Galerie-Inflation.
Aktuelle Markt-Verteilung (2025-2026):
- React: ~40% (mit Next.js Framework drum herum)
- Vue: ~15-20% (Vue 3 + Nuxt)
- Angular: ~10% (in Enterprise)
- Svelte: ~5% (wächst stark)
- Astro: ~3% (für Content-sites)
- Vanilla: ~25% (klein-Projekte, Landing Pages)
Konzeptionell sind alle ähnlich: Komponenten, State, Re-Render.
Studis sollen wissen DASS es Frameworks gibt, aber für 223015c nicht im Detail. Tiefere Behandlung in Webentwicklung-Modulen (z.B. DHBW-Curriculum).
-->
---
# Library vs. Framework
| | Library | Framework |
|--|---------|-----------|
| Wer ruft | **du** rufst die Library | das Framework ruft **dich** |
| Beispiel | jQuery, React (offiziell), Lodash | Angular, Vue, Next.js, Astro |
| Vorteil | mehr Freiheit | mehr Struktur |
| Nachteil | mehr Setup-Arbeit | weniger Flexibilität |
**„Inversion of Control":** Library = du kontrollierst, Framework = es kontrolliert dich.
<!--
Begriffsklärung:
- Library: Sammlung von Funktionen. Du entscheidest wann/wie sie aufgerufen werden. Beispiel: `_.map(...)` von Lodash.
- Framework: Skelett, das deinen Code aufruft. Du füllst nur die richtigen Stellen. Beispiel: Angular Component Lifecycle Hooks.
Grenzen sind unscharf. React positioniert sich als Library, wird mit Next.js als Framework ergänzt. Vue mit/ohne Nuxt.
Faustregel: wenn du `npm run dev` für etwas Eigenes brauchst, ist es ein Framework.
-->
---
<!-- _class: aufgabe -->
# Selbstlernen — eigenes Mini-Projekt
Wähle eines:
**A. Dark-Mode-Toggle** — Button auf einer Seite, der `dark`-Klasse am body togglet. localStorage merkt den Zustand.
**B. To-Do-App** — Form, das neue Items zur Liste hinzufügt. localStorage für Persistenz.
**C. API-Visualisierung** — fetch zu `jsonplaceholder.typicode.com/users` und Daten als Liste rendern.
**Bonus:** mit GitHub Pages deployen → öffentlich zugängliche URL.
<!--
Niederschwellige Praxis-Aufgabe. ~30-60 Minuten pro Variante.
Tools:
- VS Code als Editor
- Live-Server-Extension oder einfach Doppelklick auf HTML-Datei
- Browser-DevTools für Debug
Lernziele:
- Eigenes Mini-Projekt produzieren
- DOM-Manipulation in Praxis
- Events handhaben
- API-Anfrage stellen (Variante C)
- Code öffentlich teilen (Bonus mit GitHub Pages)
-->
---
# Zusammenfassung
**Was JS macht:** DOM manipulieren · Events behandeln · Daten holen + speichern.
**Was JS NICHT macht (ohne User-Aktion):** willkürliche Datei-/Hardware-Zugriffe.
**Patterns:** querySelector → manipulate → addEventListener.
**Frameworks (React, Vue, …):** Abstraktion + State + Komponenten — für Projekte ab ~500 Zeilen.
→ **Du hast jetzt:** verstanden wie Daten reisen (Kap 2), wie sie dargestellt werden (HTML+CSS, Kap 1+2), und wie sie *interaktiv* werden (JS, Kap 3). Das ganze moderne Web in drei Kapiteln.
<!--
Recap Kap 3 + Synthese des ganzen Kurses.
Ende des Kurses:
- Pioniere → Architektur → Internet → HTML → CSS → A11y → JS
- Studis haben einen vollständigen mentalen Bauplan des Webs
Anschluss:
- Webentwicklung-Module: tieferer Stack (React, Node, Datenbanken, Deployment)
- DHBW-Module: Industrie-Praxis-Stack
Klausur:
- Hauptsächlich Kap 1+2 (Geschichte, Netzwerk, HTML, CSS, A11y)
- JS nur konzeptionell (Block J auf Verstehen-Niveau)
-->