Touch events

Floating UI предоставляет мощные инструменты для позиционирования плавающих элементов относительно целевых объектов в DOM. Для интерактивных интерфейсов важно корректно обрабатывать касания на мобильных устройствах и сенсорных экранах. Работа с touch events позволяет адаптировать поведение всплывающих элементов, таких как тултипы, поповеры и меню, под взаимодействие пальцами.


Типы событий касания

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

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

Floating UI позволяет интегрировать эти события для управления состоянием плавающих элементов через системные адаптеры событий.


Связь Touch Events и Floating UI

Для позиционирования всплывающих элементов на мобильных устройствах важно учитывать, что:

  1. Размеры целевого элемента могут меняться из-за касания.
  2. Смещение курсора отсутствует, вместо него используется touch.clientX и touch.clientY.
  3. Фокус на элементе может быть временным, если пользователь свайпает или удерживает палец.

Floating UI предоставляет хелперы, которые упрощают работу с координатами касания:

import { computePosition, offset } from '@floating-ui/dom';

function positionFloatingElement(target, floating) {
  target.addEventListener('touchstart', (event) => {
    const touch = event.touches[0];
    computePosition(target, floating, {
      middleware: [offset(10)]
    }).then(({ x, y }) => {
      Object.assign(floating.style, {
        left: `${x}px`,
        top: `${y}px`
      });
    });
  });
}

В этом примере touchstart позволяет определить начальную позицию и вычислить координаты для плавающего элемента с учётом смещения.


Middleware и сенсорные события

Middleware в Floating UI играет ключевую роль при обработке касаний:

  • offset — добавляет смещение от цели.
  • flip — изменяет позицию при выходе за границы окна.
  • shift — корректирует положение, чтобы элемент оставался видимым.
  • arrow — позиционирует стрелку относительно цели.

Для touch-сценариев важно комбинировать offset и shift, чтобы элемент не закрывался пальцем и оставался доступным пользователю.

computePosition(target, floating, {
  middleware: [
    offset({ mainAxis: 8, crossAxis: 0 }),
    shift({ padding: 5 })
  ]
});

Динамическое обновление позиции

На сенсорных устройствах пользователь может перемещать палец, изменяя положение цели. Floating UI поддерживает динамическое обновление через функцию autoUpdate:

import { autoUpdate } from '@floating-ui/dom';

autoUpdate(target, floating, () => {
  computePosition(target, floating, {
    middleware: [offset(10), shift()]
  }).then(({ x, y }) => {
    Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
  });
});

autoUpdate реагирует на любые изменения: скролл, ресайз и касания, поддерживая корректное позиционирование плавающего элемента.


Особенности мобильного взаимодействия

  1. Удержание пальца (long press) часто используется для вызова контекстных меню. В сочетании с touchstart и таймером можно реализовать задержку перед появлением элемента.
  2. Свайпы и жесты — при активном touchmove можно временно скрывать плавающий элемент или изменять его позицию динамически.
  3. Синхронизация с Pointer Events — на современных устройствах стоит учитывать, что события pointerdown и pointermove могут работать параллельно с touch events.

Практические советы

  • Всегда использовать touches[0] для получения координат первого касания.
  • Минимизировать задержку при позиционировании, чтобы интерфейс оставался отзывчивым.
  • При комбинированной поддержке мыши и сенсорного ввода следует объединять обработчики через универсальные функции.
  • Тестировать на реальных устройствах, так как поведение сенсорных событий может различаться в браузерах.

Пример комплексного touch-позиционирования

import { computePosition, offset, flip, shift, autoUpdate } from '@floating-ui/dom';

const target = document.querySelector('#button');
const floating = document.querySelector('#tooltip');

target.addEventListener('touchstart', (event) => {
  const touch = event.touches[0];
  
  const cleanup = autoUpdate(target, floating, () => {
    computePosition(target, floating, {
      middleware: [offset(10), flip(), shift({ padding: 5 })]
    }).then(({ x, y }) => {
      Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
    });
  });

  target.addEventListener('touchend', () => {
    floating.style.display = 'none';
    cleanup();
  }, { once: true });
});

Этот пример сочетает динамическое обновление, смещение и обработку окончания касания, обеспечивая корректное поведение всплывающего элемента на мобильных устройствах.


Хотите, я подготовлю следующую часть с обработкой сложных жестов и мультитач для Floating UI?