Signatur
Beschreibung
Das wheel-Ereignis wird an einem Element ausgelöst, wenn der Benutzer das Rad eines Zeigegeräts dreht. Das kann ein Mausrad sein, aber auch ein Touchpad mit Zwei-Finger-Geste oder ein Trackball. Der Handler erhält ein WheelEvent mit den Eigenschaften deltaX, deltaY, deltaZ und deltaMode. Dazu kommen alle Eigenschaften von MouseEvent, also z. B. clientX, ctrlKey und shiftKey.
Registrieren kannst du den Handler auf zwei Wegen: mit element.addEventListener("wheel", handler) oder über die Eigenschaft element.onwheel = handler. Das Ereignis steigt im DOM nach oben (bubbles) und lässt sich abbrechen (cancelable). Mit event.preventDefault() unterdrückst du also das Standardverhalten, etwa das Scrollen der Seite oder das Zoomen mit Strg + Rad.
Typische Einsatzfälle sind:
- eigene Zoom-Steuerung, z. B. für Karten, Bildbetrachter oder Canvas
- horizontales Scrollen einer Leiste mit dem vertikalen Mausrad
- das Durchblättern von Werten, z. B. Zahlen, Folien oder Galeriebilder
Wichtig: wheel ist nicht dasselbe wie scroll. wheel meldet die Eingabe des Geräts, auch wenn dadurch gar nichts scrollt. scroll feuert erst, wenn sich die Scroll-Position tatsächlich geändert hat. Wenn du nur auf Scrollen reagieren willst, ist scroll meist die bessere Wahl.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname, hier immer "wheel". |
|
| $handler Pflicht | (event: WheelEvent) => void | Callback-Funktion, die ein WheelEvent erhält. Wichtige Eigenschaften: deltaX, deltaY, deltaZ und deltaMode. deltaMode gibt die Einheit an: 0 = Pixel, 1 = Zeilen, 2 = Seiten. |
|
| $options | boolean | { capture?: boolean, once?: boolean, passive?: boolean, signal?: AbortSignal } | { passive: false } (auf window/document/body in Chrome/Firefox: passive: true) | Optionen für den Listener. passive: false ist nötig, wenn du preventDefault() aufrufen willst. signal erlaubt das Entfernen des Listeners über einen AbortController. |
Rückgabewert
addEventListener gibt nichts zurück. Den Rückgabewert des Handlers wertet der Browser ebenfalls nicht aus. Um das Standardverhalten zu verhindern, rufst du event.preventDefault() auf.Beispiele
Zoom mit dem Mausrad auf einem Bild
const img = document.querySelector('#bild');
let scale = 1;
const onWheel = (event) => {
event.preventDefault(); // Seitenscroll unterdrücken
// Negatives deltaY = Rad nach oben = hineinzoomen
scale += event.deltaY * -0.001;
scale = Math.min(Math.max(0.25, scale), 4); // auf 0,25–4 begrenzen
img.style.transform = `scale(${scale})`;
console.log('Zoom:', scale.toFixed(2));
};
// passive: false ist nötig, damit preventDefault() wirkt
img.addEventListener('wheel', onWheel, { passive: false });
Horizontales Scrollen einer Leiste mit dem vertikalen Mausrad
const leiste = document.querySelector('.thumbnail-leiste');
leiste.addEventListener('wheel', (event) => {
// Nur eingreifen, wenn überwiegend vertikal gescrollt wird
if (Math.abs(event.deltaY) <= Math.abs(event.deltaX)) return;
event.preventDefault();
// deltaMode 1 = Zeilen (z. B. Firefox) → grob in Pixel umrechnen
const faktor = event.deltaMode === 1 ? 16 : 1;
leiste.scrollLeft += event.deltaY * faktor;
}, { passive: false });
Handler per onwheel setzen und Listener wieder entfernen
const box = document.querySelector('#box');
// Variante 1: on-Property (nur ein Handler möglich)
box.onwheel = (event) => {
console.log(`deltaY: ${event.deltaY}, Strg: ${event.ctrlKey}`);
};
// Variante 2: addEventListener + removeEventListener
const logRichtung = (event) => {
console.log(event.deltaY > 0 ? 'runter' : 'hoch');
};
box.addEventListener('wheel', logRichtung);
// Nach 5 Sekunden beide Handler entfernen
setTimeout(() => {
box.removeEventListener('wheel', logRichtung);
box.onwheel = null;
console.log('wheel-Handler entfernt');
}, 5000);
Seitenweises Blättern mit Drosselung über AbortController
const folien = document.querySelectorAll('.folie');
let index = 0;
let gesperrt = false;
const controller = new AbortController();
document.querySelector('#praesentation').addEventListener('wheel', (event) => {
event.preventDefault();
if (gesperrt) return; // Touchpads liefern viele Events pro Geste
gesperrt = true;
index = Math.max(0, Math.min(folien.length - 1, index + Math.sign(event.deltaY)));
folien[index].scrollIntoView({ behavior: 'smooth' });
console.log('Folie', index + 1);
setTimeout(() => { gesperrt = false; }, 600);
}, { passive: false, signal: controller.signal });
// Später: controller.abort() entfernt den Listener
// Wichtig · Fallstricke
- Passive Listener: In Chrome, Edge und Firefox sind
wheel-Listener aufwindow,documentunddocument.bodystandardmäßigpassive: true. Dort bleibtpreventDefault()ohne Wirkung, und die Konsole zeigt eine Warnung. Wenn du das Scrollen verhindern willst, gib{ passive: false }ausdrücklich an. Blockiere das Scrollen aber nur, wenn es nötig ist, denn nicht-passive Listener können das Scrollen ruckelig machen. - Richtung und Größe der Deltas sind nicht einheitlich: Die Werte unterscheiden sich je nach Browser, Betriebssystem und Gerät. Firefox liefert zum Teil
deltaMode = 1(Zeilen), andere Browser liefern Pixel. Touchpads erzeugen viele kleine Events hintereinander, oft mit Trägheit (Nachlauf). Verlass dich deshalb nicht auf feste Werte wie100. Nutze besserMath.sign(deltaY)und drossle die Verarbeitung. - Pinch-Zoom: Die Zwei-Finger-Zoomgeste auf Touchpads kommt in Chromium-Browsern und Firefox als
wheel-Event mitctrlKey === truean. - Veraltete Ereignisse:
mousewheelundDOMMouseScrollsind nicht standardisiert und veraltet. Nutze nur nochwheel. - Barrierefreiheit: Wenn du das Scrollen komplett abfängst, bekommen Tastatur- und Screenreader-Nutzer davon nichts mit. Biete deshalb zusätzlich eine Bedienung per Tastatur oder über Schaltflächen an.
- Kein Ersatz für
scroll: Scrollen per Tastatur, Scrollleiste oder Touch-Wischen löst keinwheel-Ereignis aus.