====== 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'); } }); });