Signatur
Beschreibung
Das touchmove-Ereignis gehört zur Touch Events API und feuert wiederholt, solange ein Finger (oder Stift) nach einem touchstart über die Oberfläche bewegt wird. Das Ereignis wird immer an das Element geschickt, auf dem die Berührung begonnen hat, auch wenn der Finger dieses Element längst verlassen hat.
Der Handler bekommt ein TouchEvent. Die wichtigsten Eigenschaften sind:
touches: alle Berührungspunkte, die gerade auf der Oberfläche liegentargetTouches: die Punkte, die auf dem Ziel-Element begonnen habenchangedTouches: die Punkte, die sich seit dem letzten Ereignis bewegt haben
Jedes Touch-Objekt hat eine eindeutige identifier sowie die Koordinaten clientX/Y, pageX/Y und screenX/Y.
Typische Anwendungen sind Wisch-Gesten, Drag-and-Drop auf Mobilgeräten, Zeichenflächen, Slider und Pinch-Zoom. Du kannst den Handler per addEventListener("touchmove", …) oder über die Eigenschaft element.ontouchmove registrieren. Für neuen Code, der Maus, Stift und Touch gleich behandeln soll, sind die Pointer Events (pointermove) meist die bessere Wahl.
Das Ereignis ist abbrechbar (cancelable), bubbelt und kann mit event.preventDefault() das native Scrollen oder Zoomen verhindern. Das klappt aber nur, wenn der Listener nicht passiv ist.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignistyp, hier "touchmove". |
|
| $handler Pflicht | (event: TouchEvent) => void | Callback-Funktion. Sie bekommt ein TouchEvent mit touches, targetTouches und changedTouches. |
|
| $options | boolean | { passive?: boolean, capture?: boolean, once?: boolean, signal?: AbortSignal } | { passive: true } auf window/document/body in Chrome und Firefox | Optionen für den Listener. Mit passive: false darf der Handler preventDefault() aufrufen. Mit signal lässt sich der Listener über einen AbortController wieder entfernen. |
Rückgabewert
addEventListener gibt undefined zurück. Der Handler bekommt ein TouchEvent.Beispiele
Fingerposition verfolgen (addEventListener)
const area = document.querySelector('#touch-area');
area.addEventListener('touchmove', (event) => {
// changedTouches enthält nur die Punkte, die sich bewegt haben
for (const touch of event.changedTouches) {
console.log(`Finger ${touch.identifier}: x=${Math.round(touch.clientX)}, y=${Math.round(touch.clientY)}`);
}
}, { passive: true });
Element per Touch verschieben und Scrollen verhindern
const box = document.querySelector('.draggable');
let offsetX = 0;
let offsetY = 0;
box.addEventListener('touchstart', (e) => {
const t = e.targetTouches[0];
const rect = box.getBoundingClientRect();
offsetX = t.clientX - rect.left;
offsetY = t.clientY - rect.top;
}, { passive: true });
// passive: false, damit preventDefault() das Scrollen der Seite unterbindet
box.addEventListener('touchmove', (e) => {
e.preventDefault();
const t = e.targetTouches[0];
box.style.transform = `translate(${t.clientX - offsetX}px, ${t.clientY - offsetY}px)`;
}, { passive: false });
Wischrichtung erkennen und Listener wieder entfernen
const slider = document.querySelector('.slider');
let startX = 0;
const onMove = (e) => {
const deltaX = e.touches[0].clientX - startX;
if (Math.abs(deltaX) > 50) {
console.log(deltaX > 0 ? 'Wisch nach rechts' : 'Wisch nach links');
// Nach erkannter Geste Listener entfernen
slider.removeEventListener('touchmove', onMove);
}
};
slider.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
slider.addEventListener('touchmove', onMove, { passive: true });
}, { passive: true });
Pinch-Abstand über die on-Property messen
const img = document.querySelector('#zoom-image');
img.ontouchmove = (e) => {
if (e.touches.length !== 2) return;
const [a, b] = e.touches;
const distance = Math.hypot(b.clientX - a.clientX, b.clientY - a.clientY);
console.log(`Abstand: ${distance.toFixed(0)} px`);
};
// Handler wieder entfernen:
// img.ontouchmove = null;
// Wichtig · Fallstricke
- Passive Listener: Chrome, Edge und Firefox behandeln
touchmove-Listener aufwindow,documentunddocument.bodystandardmäßig alspassive: true. Ein Aufruf vonpreventDefault()wird dort ignoriert und erzeugt eine Konsolenwarnung. Wenn du Scrollen gezielt unterbinden willst, gib{ passive: false }ausdrücklich an. Oft ist die CSS-Eigenschafttouch-action: nonedie schnellere und sauberere Lösung. - Performance:
touchmovekann sehr oft feuern, bis zur Bildwiederholrate und darüber. Aufwendige DOM-Änderungen solltest du perrequestAnimationFramebündeln. Nicht-passive Listener können das Scrollen spürbar verzögern. - Ziel-Element:
event.targetbleibt das Element, auf dem die Berührung begonnen hat, auch wenn der Finger es verlässt. Das Element unter dem Finger findest du mitdocument.elementFromPoint(touch.clientX, touch.clientY). - Entfernte Elemente: Wird das Start-Element während der Geste aus dem DOM entfernt, kommen die weiteren
touchmove-Ereignisse nicht mehr beim übergeordneten Element an. Das Element sollte daher bistouchendim DOM bleiben. - Kompatibilität: Alle mobilen Browser unterstützen das Ereignis. Auf Desktop-Browsern feuert es nur mit Touch-Hardware; Safari auf macOS unterstützt Touch Events nicht. Wenn du Maus, Stift und Touch einheitlich behandeln willst, nimm
pointermove. Prüfe die Unterstützung mit'ontouchstart' in window. - Nach
touchcancel(zum Beispiel bei einem Systemdialog) kommen keine weiterentouchmove-Ereignisse. Setze deinen Gesten-Zustand dort zurück.