====== LU04b – Events & State ======
===== Events & EventListener =====
Ein **Event** ist ein Signal, das der Browser aussendet, wenn etwas passiert – ein Klick, eine Tastatureingabe, eine Berührung. Mit einem **EventListener** registrieren Sie eine Funktion, die auf dieses Signal reagiert.
const btn = document.querySelector('#mein-button');
btn.addEventListener('click', () => {
console.log('Geklickt!');
});
**Verbindung zum Alarado-Projekt:** Beim Dark/Light Toggle haben Sie bereits ''addEventListener'' verwendet: ''checkbox.addEventListener('change', toggleTheme)''. Heute nutzen wir dasselbe Muster für das Accordion.
===== Die wichtigsten Event-Typen =====
==== Allgemeine Interaktion ====
^ Event ^ Wann? ^ Einsatz ^
| ''click'' | Maustaste oder Tap (mit ~300ms Verzögerung) | Buttons, Links, Toggle |
| ''change'' | Wert geändert + Fokus verloren | Checkbox, Select |
| ''input'' | Wert ändert sich sofort (jedes Zeichen) | Live-Suche, Zeichenzähler |
| ''submit'' | Formular wird abgesendet | Formular-Validierung |
| ''keydown'' | Taste gedrückt | Shortcuts, Keyboard-Navigation |
| ''scroll'' | Seite wird gescrollt | Sticky Nav, Lazy Loading |
| ''DOMContentLoaded'' | HTML vollständig geparst | JS-Initialisierung |
// Tastatur: Escape schliesst ein Element
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
panel.classList.remove('open');
}
});
// JS erst ausführen, wenn das DOM bereit ist
document.addEventListener('DOMContentLoaded', () => {
const buttons = document.querySelectorAll('.accordion-btn');
// ...
});
===== Pointer Events (moderner Standard) =====
Pointer Events sind der **aktuelle Standard** für alle Zeigereingaben. Sie decken Maus, Touchscreen und Stift mit einem einzigen Event-System ab – und ersetzen damit die älteren separaten Maus- und Touch-Events.
^ Event ^ Wann? ^
| ''pointerdown'' | Zeiger gedrückt / Finger berührt Bildschirm |
| ''pointermove'' | Zeiger bewegt sich |
| ''pointerup'' | Zeiger losgelassen / Finger abgehoben |
| ''pointerenter'' | Zeiger betritt Element |
| ''pointerleave'' | Zeiger verlässt Element |
| ''pointercancel'' | Interaktion abgebrochen (z.B. Anruf, Scroll) |
==== Beispiel: Hover und Klick mit Pointer Events ====
const box = document.querySelector('.box');
box.addEventListener('pointerenter', () => {
box.classList.add('hovered');
});
box.addEventListener('pointerleave', () => {
box.classList.remove('hovered');
});
box.addEventListener('pointerdown', (event) => {
// Welches Gerät wird verwendet?
if (event.pointerType === 'touch') {
console.log('Touch-Eingabe');
} else if (event.pointerType === 'mouse') {
console.log('Maus-Eingabe');
} else if (event.pointerType === 'pen') {
console.log('Stift, Druck:', event.pressure);
}
});
**Ältere Alternativen:** ''mousedown'' / ''mousemove'' / ''mouseup'' funktionieren nur mit der Maus. ''touchstart'' / ''touchmove'' / ''touchend'' nur auf Touchscreens. Pointer Events ersetzen beide – verwenden Sie in neuen Projekten immer Pointer Events.
===== Das Event-Objekt =====
Alle Handler erhalten automatisch ein **Event-Objekt** als Parameter:
^ Eigenschaft / Methode ^ Beschreibung ^
| ''event.target'' | Das Element, das das Event ausgelöst hat |
| ''event.type'' | Name des Events (z.B. ''pointerdown'') |
| ''event.preventDefault()'' | Standardverhalten verhindern (z.B. Link nicht öffnen) |
| ''event.stopPropagation()'' | Event nicht weiter nach oben weitergeben |
// Beispiel: Link-Klick abfangen
document.querySelector('a').addEventListener('click', (event) => {
event.preventDefault();
console.log('Navigation verhindert');
});
===== State – Zustand im UI =====
**State** (Zustand) ist der aktuelle Stand Ihrer Benutzeroberfläche. Beim Accordion hat jedes Panel zwei mögliche Zustände: **offen** oder **geschlossen**.
Das Muster kennen Sie bereits vom Toggle:
^ Zustand ^ Klasse gesetzt? ^ ''aria-expanded'' ^
| geschlossen | ''.panel'' (kein ''.open'') | ''"false"'' |
| offen | ''.panel.open'' | ''"true"'' |
==== State aus dem DOM lesen ====
Sie können den Zustand direkt aus dem DOM ablesen, ohne eine eigene Variable zu führen:
const panel = document.querySelector('.panel');
const btn = document.querySelector('.accordion-btn');
btn.addEventListener('click', () => {
const istOffen = panel.classList.contains('open');
if (istOffen) {
panel.classList.remove('open');
btn.setAttribute('aria-expanded', 'false');
} else {
panel.classList.add('open');
btn.setAttribute('aria-expanded', 'true');
}
});
==== Alle anderen Panels schliessen ====
Bei einem klassischen Accordion soll immer nur ein Panel offen sein:
const buttons = document.querySelectorAll('.accordion-btn');
buttons.forEach(btn => {
btn.addEventListener('click', () => {
const panel = btn.nextElementSibling;
const istOffen = panel.classList.contains('open');
// Alle Panels schliessen
buttons.forEach(andererBtn => {
andererBtn.nextElementSibling.classList.remove('open');
andererBtn.setAttribute('aria-expanded', 'false');
});
// Dieses Panel öffnen (nur wenn es vorher zu war)
if (!istOffen) {
panel.classList.add('open');
btn.setAttribute('aria-expanded', 'true');
}
});
});