Touch events

Фреймворк Fresh построен на базе Deno и ориентирован на современный подход к рендерингу веб-приложений с минимальным использованием клиентского JavaScript. Работа с сенсорными событиями (Touch events) в Fresh требует понимания как серверной, так и клиентской частей, так как обработка событий происходит преимущественно на клиенте, но может быть интегрирована с серверной логикой через сигналы и состояния компонентов.


Типы сенсорных событий

В JavaScript существуют стандартные события для сенсорных экранов:

  • touchstart — возникает при касании элемента пальцем.
  • touchmove — срабатывает при перемещении пальца по экрану.
  • touchend — вызывается при отпускании пальца.
  • touchcancel — срабатывает, когда система прерывает сенсорное взаимодействие (например, входящий звонок на мобильном устройстве).

Каждое из этих событий содержит объект TouchEvent, который включает массив touches (все активные касания), targetTouches (касания на конкретном элементе) и changedTouches (касания, изменившие состояние в текущем событии).


Интеграция Touch events в Fresh

Fresh использует islands architecture, что позволяет привязывать интерактивные компоненты с минимальным JavaScript. Для работы с сенсорными событиями создаются клиентские компоненты:

/** @jsx h */
import { h } from "preact";
import { useState } from "preact/hooks";

export default function TouchTracker() {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleTouchMove = (e) => {
    const touch = e.touches[0];
    setPosition({ x: touch.clientX, y: touch.clientY });
  };

  return (
    <div
      onTouchM ove={handleTouchMove}
      style={{
        width: "100vw",
        height: "100vh",
        backgroundColor: "#f0f0f0",
        touchAction: "none",
      }}
    >
      <p>Координаты: {position.x}, {position.y}</p>
    </div>
  );
}

Ключевые моменты:

  • touchAction: "none" — отключает стандартное поведение браузера при свайпах и масштабировании, позволяя полностью контролировать жесты.
  • Использование useState для отслеживания координат позволяет обновлять интерфейс в реальном времени без перезагрузки страницы.
  • onTouchMove привязывается напрямую к элементу DOM, что обеспечивает нативное реагирование на события.

Обработка мультитача

Для поддержки нескольких пальцев необходимо использовать массив touches. Пример отслеживания двух касаний одновременно:

const handleMultiTouch = (e) => {
  if (e.touches.length >= 2) {
    const touch1 = e.touches[0];
    const touch2 = e.touches[1];
    const distance = Math.hypot(
      touch2.clientX - touch1.clientX,
      touch2.clientY - touch1.clientY
    );
    console.log("Расстояние между пальцами:", distance);
  }
};

Использование этого подхода позволяет реализовать жесты pinch-to-zoom или multi-finger swipe без сторонних библиотек.


Связь с серверной частью

Fresh позволяет использовать server-side rendering вместе с интерактивными компонентами. Для передачи данных о касаниях на сервер можно использовать:

  • fetch API внутри обработчиков Touch events.
  • signals для синхронизации состояния между клиентом и сервером.

Пример передачи координат на сервер:

const sendPosition = async (x, y) => {
  await fetch("/api/touch", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ x, y }),
  });
};

const handleTouchMove = (e) => {
  const touch = e.touches[0];
  sendPosition(touch.clientX, touch.clientY);
};

На серверной стороне можно использовать API routes Fresh для обработки POST-запросов.


Оптимизация производительности

При работе с touch-событиями важно учитывать производительность:

  • Использовать passive event listeners, если событие не вызывает preventDefault().
  • Минимизировать количество ререндеров UI при frequent events (touchmove) с помощью requestAnimationFrame или дебаунсинга.
  • Ограничивать подписку на события только необходимыми элементами, чтобы снизить нагрузку на основной поток.

Пример с requestAnimationFrame:

let ticking = false;

const handleTouchMove = (e) => {
  if (!ticking) {
    window.requestAnimationFrame(() => {
      const touch = e.touches[0];
      setPosition({ x: touch.clientX, y: touch.clientY });
      ticking = false;
    });
    ticking = true;
  }
};

Особенности мобильных браузеров

  • iOS Safari по умолчанию блокирует некоторые жесты, такие как свайп назад/вперед. Использование touch-action позволяет предотвратить это.
  • В Android Chrome возможны различия в точности координат и чувствительности сенсора, что важно учитывать при реализации интерфейсов с мультитачем.
  • Для горизонтальных и вертикальных жестов рекомендуется тестировать на реальных устройствах, так как симуляторы не всегда точно имитируют поведение.

Комбинация с другими событиями

События touchstart, touchmove и touchend можно комбинировать с pointer-событиями (pointerdown, pointermove) для создания универсальных интерфейсов, работающих как на десктопе, так и на мобильных устройствах. В Fresh это удобно реализуется через Preact-хуки и props компонентов.


Система Touch events в Fresh предоставляет мощный инструмент для создания интерактивных мобильных интерфейсов с минимальной нагрузкой на клиентский код, позволяя одновременно использовать серверную обработку и современные возможности браузеров.