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:
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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: '' -->
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
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)
|
||||
-->
|
||||
Reference in new issue
Block a user