Touch устройства

Popper.js — это библиотека для позиционирования всплывающих элементов, таких как тултипы, поповеры и dropdown-меню. На touch-устройствах возникают специфические особенности взаимодействия, которые требуют отдельного подхода при работе с Popper.js.


Особенности взаимодействия на touch

На устройствах с сенсорным экраном отсутствует стандартный курсор мыши. События mouseenter и mouseleave, привычные для десктопа, часто не срабатывают или обрабатываются с задержкой. Вместо них используются события touchstart, touchend и touchmove. Это важно учитывать при активации всплывающих элементов через Popper.js.

Ключевой момент: взаимодействие должно быть основано на событиях касания, а не на hover.


Настройка Popper.js для touch

Popper.js не отвечает за события активации элементов, но важно правильно интегрировать библиотеку с обработчиками событий touch. Например:

import { createPopper } from '@popperjs/core';

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

let popperInstance;

function show() {
  popperInstance = createPopper(button, tooltip, {
    placement: 'top',
    modifiers: [
      {
        name: 'offset',
        options: {
          offset: [0, 8],
        },
      },
      {
        name: 'preventOverflow',
        options: {
          padding: 5,
        },
      },
    ],
  });
  tooltip.setAttribute('data-show', '');
}

function hide() {
  tooltip.removeAttribute('data-show');
  if (popperInstance) {
    popperInstance.destroy();
    popperInstance = null;
  }
}

button.addEventListener('touchstart', (event) => {
  event.preventDefault(); // предотвращает двойное срабатывание
  show();
});

document.addEventListener('touchend', (event) => {
  if (!button.contains(event.target)) {
    hide();
  }
});

Пояснения к коду:

  • touchstart активирует Popper, создавая всплывающий элемент.
  • touchend на документе позволяет скрывать Popper, если пользователь коснулся вне элемента.
  • preventDefault() необходим, чтобы избежать конфликтов с click, который может сработать после touch.

Обработка жестов

Для touch-устройств полезно учитывать такие жесты, как свайпы и длительное удержание. Popper.js можно использовать совместно с библиотеками распознавания жестов (например, Hammer.js) для:

  • Показа тултипов при долгом нажатии (longpress).
  • Перемещения поповеров вместе с пальцем (drag & drop).
// Пример использования Hammer.js
const hammer = new Hammer(button);
hammer.on('press', () => {
  show();
});
hammer.on('pan', (ev) => {
  if (popperInstance) {
    popperInstance.update(); // пересчет позиции при движении пальца
  }
});

Адаптация позиции и видимости

На touch-устройствах часто приходится учитывать меньший экран и возможное наложение системной клавиатуры. В Popper.js доступны модификаторы для адаптации:

  • flip — автоматически меняет сторону отображения, если всплывающий элемент выходит за границы экрана.
  • preventOverflow — ограничивает выход за видимую область.
  • offset — добавляет отступ, предотвращая наложение на палец пользователя.
modifiers: [
  { name: 'flip', options: { fallbackPlacements: ['bottom', 'right', 'left'] } },
  { name: 'preventOverflow', options: { padding: 8 } },
  { name: 'offset', options: { offset: [0, 10] } },
]

Рекомендация: для touch-интерфейсов увеличить padding и offset по сравнению с десктопом, чтобы обеспечить удобный доступ к элементу.


Учет задержки и двойного касания

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

  • Ввести минимальную задержку перед отображением Popper (например, 150–200 мс).
  • Игнорировать повторное касание, если элемент уже активен.
let touchTimeout;

button.addEventListener('touchstart', (event) => {
  event.preventDefault();
  if (touchTimeout) clearTimeout(touchTimeout);
  touchTimeout = setTimeout(() => show(), 150);
});

document.addEventListener('touchend', () => {
  if (touchTimeout) clearTimeout(touchTimeout);
});

Интеграция с скроллом

На мобильных устройствах скролл может сдвинуть родительский элемент. Popper.js имеет модификатор eventListeners, который автоматически обновляет позицию при скролле или изменении размера окна:

modifiers: [
  { name: 'eventListeners', enabled: true },
]

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


Советы по оптимизации

  • Использовать touchstart вместо mouseover.
  • Добавлять preventDefault и stopPropagation только при необходимости, чтобы не нарушать нативное поведение браузера.
  • Контролировать количество одновременно активных Popper-элементов, чтобы не создавать лишние инстансы.
  • Применять computeStyles с опцией adaptive: true, чтобы Popper корректно реагировал на повороты экрана и изменение размеров окна.

Touch-устройства требуют более внимательной настройки Popper.js, учитывая особенности сенсорного ввода, жестов и ограниченного пространства экрана. Использование правильных модификаторов, событий и контроля жизненного цикла Popper обеспечивает стабильную и удобную работу всплывающих элементов.