Preact использует синтетическую систему событий, совместимую с DOM API и во многом повторяющую модель React. Touch-события обрабатываются как обычные DOM-события, но регистрируются через JSX-атрибуты и проходят через унифицированный механизм делегирования.
Базовый набор touch-событий:
Каждое событие получает объект TouchEvent, содержащий
коллекции:
touches — все активные касанияtargetTouches — касания, начавшиеся на текущем
элементеchangedTouches — касания, изменившиеся в данном
событииPreact не оборачивает TouchEvent в дополнительный слой,
поэтому доступ к свойствам и методам идентичен нативному DOM.
function TouchArea() {
const handleStart = (e) => {
console.log(e.touches.length);
};
return <div onTouchSt art={handleStart}>...</div>;
}
Touch-события имеют ряд принципиальных отличий от mouse-событий:
clientX,
clientY)touchend (возможен
touchcancel)Для точного контроля над поведением часто требуется отключение стандартных жестов браузера.
.touch-area {
touch-action: none;
}
Свойство touch-action критически важно для корректной
обработки жестов в мобильных интерфейсах.
Метод preventDefault() позволяет блокировать прокрутку и
масштабирование, но с ограничениями. В современных браузерах
touch-события часто являются passive по умолчанию.
В Preact для корректной работы preventDefault()
необходимо явно отключить passive-режим через CSS
(touch-action) или использовать onTouchMove
без ожидания блокировки.
const handleMove = (e) => {
e.preventDefault();
};
Без touch-action: none вызов
preventDefault() может быть проигнорирован.
Для реализации жестов требуется хранить начальные координаты касания и отслеживать изменения.
import { useRef } from 'preact/hooks';
function DragBlock() {
const startX = useRef(0);
const startY = useRef(0);
const onSt art = (e) => {
const t = e.touches[0];
startX.current = t.clientX;
startY.current = t.clientY;
};
const onM ove = (e) => {
const t = e.touches[0];
const dx = t.clientX - startX.current;
const dy = t.clientY - startY.current;
console.log(dx, dy);
};
return <div onTouchSt art={onStart} onTouchM ove={onMove} />;
}
Использование useRef позволяет сохранять данные между
событиями без перерендера компонента.
Tap определяется как короткое касание без значительного смещения.
const MAX_DURATION = 200;
const MAX_DISTANCE = 10;
Фиксируется время начала и координаты. При touchend
сравниваются длительность и смещение.
Long press реализуется через таймер:
let timer = setTimeout(() => {
// long press
}, 500);
Таймер очищается при touchend или
touchmove.
Swipe определяется направлением и скоростью движения.
Основные параметры:
const dx = endX - startX;
const dy = endY - startY;
if (Math.abs(dx) > Math.abs(dy)) {
if (dx > 0) swipeRight();
else swipeLeft();
}
Минимальное расстояние (например, 30–50px) предотвращает ложные срабатывания.
Pinch использует два одновременных касания.
function distance(t1, t2) {
return Math.hypot(
t2.clientX - t1.clientX,
t2.clientY - t1.clientY
);
}
При touchstart с двумя точками сохраняется исходное
расстояние. При touchmove вычисляется новое расстояние и
коэффициент масштабирования.
scale = currentDistance / initialDistance;
Preact полностью поддерживает Pointer Events, которые объединяют mouse, touch и stylus.
<div
onPointerD own={start}
onPointerM ove={move}
onPointe rUp={end}
/>
Преимущества:
pressure)Для современных браузеров Pointer Events предпочтительнее touch-событий.
.pointer-area {
touch-action: none;
}
Частые touchmove события могут вызывать перегрузку
основного потока.
Практики оптимизации:
touchmoverequestAnimationFrameuseReflet rafId = null;
const onM ove = (e) => {
if (rafId) return;
rafId = requestAnimationFrame(() => {
// обновление
rafId = null;
});
};
Preact совместим с библиотеками:
При интеграции предпочтительно использовать ref для
доступа к DOM-элементу.
const ref = useRef(null);
useEffect(() => {
const manager = new Hammer(ref.current);
manager.on('swipe', handler);
}, []);
touch-actionsetState в каждом
touchmovetouchcancelclick после touch на мобильных
устройствахХорошей практикой является вынесение логики жестов в кастомные хуки.
function useSwipe(ref, callback) {
// логика
}
Это упрощает повторное использование, тестирование и поддержку кода.
touch-actionpreventDefaultУниверсальный подход — Pointer Events с fallback на Touch Events при необходимости.