Touch events обработка

Shopify Draggable — это библиотека для реализации drag-and-drop интерфейсов на веб-страницах. Одним из ключевых аспектов её работы является корректная обработка событий касания (touch events), которые позволяют пользователю перетаскивать элементы на мобильных устройствах и сенсорных экранах. В Draggable touch-события обрабатываются параллельно с мышиными событиями, обеспечивая унифицированный интерфейс для всех устройств.


События касания и их роль

В браузерах существует три основных события касания:

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

Draggable использует эти события для имитации поведения drag-and-drop. Каждое событие конвертируется в событие Draggable с соответствующими координатами и метаданными.


Инициализация Draggable с поддержкой touch

Для корректной работы на сенсорных устройствах нужно убедиться, что Draggable включён с модулем TouchSensor:

import { Draggable, Plugins } from '@shopify/draggable';

const container = document.querySelector('.draggable-container');

const draggable = new Draggable(container, {
  draggable: '.draggable-item',
  plugins: [Plugins.TouchSensor],
});

TouchSensor автоматически отслеживает touchstart, touchmove и touchend, создавая внутренние события drag:start, drag:move и drag:stop.


Преобразование координат

Touch-события возвращают координаты в виде массива touches. Для работы Draggable важен первый касательный объект:

element.addEventListener('touchstart', (event) => {
  const touch = event.touches[0];
  console.log('X:', touch.clientX, 'Y:', touch.clientY);
});

Draggable использует эти координаты для вычисления смещения элемента относительно исходной позиции. Это обеспечивает плавное перемещение даже при множественных касаниях.


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

  1. Событие preventDefault Без вызова event.preventDefault() браузер может интерпретировать движение пальца как прокрутку страницы. Draggable делает это автоматически в TouchSensor, чтобы избежать конфликта между drag и scroll.

  2. Множественные касания Draggable отслеживает только первый палец (touches[0]). Второй или третий касания игнорируются, чтобы не нарушать логику drag.

  3. Высокая чувствительность TouchSensor применяет пороговое значение движения (distance threshold) перед началом drag, предотвращая случайные срабатывания при легком прикосновении.


Обработка событий drag с touch

Draggable предоставляет унифицированные события, которые работают как для мыши, так и для touch:

draggable.on('drag:start', (event) => {
  console.log('Начало перетаскивания:', event.source);
});

draggable.on('drag:move', (event) => {
  console.log('Перемещение:', event.sensorEvent.clientX, event.sensorEvent.clientY);
});

draggable.on('drag:stop', (event) => {
  console.log('Конец перетаскивания:', event.source);
});

Объект sensorEvent содержит исходное событие (MouseEvent или TouchEvent) и координаты. Для touch это event.sensorEvent.touches[0].


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

  • Проблема с pointer-events Элементы, на которых установлен pointer-events: none, не будут реагировать на drag. Для touch это также критично.

  • Прокрутка внутри контейнера Если контейнер имеет вертикальный скролл, Draggable позволяет определить приоритет: drag или scroll. Для этого используется опция scrollable внутри TouchSensor:

plugins: [new Plugins.TouchSensor({ scrollable: true })]
  • Высота и ширина элемента При drag элемент может быть скопирован в виде mirror, который создаётся автоматически для touch. Это снижает визуальный лаг и предотвращает конфликт с layout страницы.

Отладка touch-событий

  1. Использовать console.log(event.touches) для отслеживания координат.
  2. Проверять наличие event.preventDefault() для предотвращения скролла.
  3. Тестировать на реальных устройствах, поскольку эмуляция в браузере не всегда точно отражает сенсорное поведение.

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

На мобильных устройствах важно минимизировать перерисовки. Рекомендуется:

  • Использовать requestAnimationFrame для обновления позиции mirror.
  • Сохранять начальные координаты и смещения, чтобы не вычислять их каждый touchmove.
  • Ограничивать drag на сложных DOM-структурах с большим количеством элементов.

Touch-события в Shopify Draggable позволяют создавать плавный, интуитивный drag-and-drop интерфейс на мобильных устройствах без дополнительных библиотек. Понимание их структуры и правильная настройка TouchSensor — ключ к корректной и производительной реализации.