Тач-события

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


Базовые принципы работы с touch-событиями

В основе лежит использование стандартных событий браузера:

  • touchstart
  • touchmove
  • touchend

Noty автоматически отслеживает эти события для каждого уведомления и применяет их для реализации интерактивного поведения.

Ключевые задачи:

  • определение направления свайпа
  • вычисление расстояния перемещения
  • решение: закрывать уведомление или возвращать его в исходное положение

Свайп для закрытия уведомления

Механика

При касании уведомления фиксируется начальная точка (touchstart). Далее при перемещении (touchmove) вычисляется смещение по оси X. Если пользователь отпускает палец (touchend) и смещение превышает заданный порог — уведомление закрывается.

Пример логики (упрощённый)

let startX = 0;
let currentX = 0;

element.addEventListener('touchstart', (e) => {
  startX = e.touches[0].clientX;
});

element.addEventListener('touchmove', (e) => {
  currentX = e.touches[0].clientX;
  let diff = currentX - startX;

  element.style.transform = `translateX(${diff}px)`;
});

element.addEventListener('touchend', () => {
  let diff = currentX - startX;

  if (Math.abs(diff) > 100) {
    closeNotification();
  } else {
    element.style.transform = 'translateX(0)';
  }
});

В Noty аналогичная логика встроена и не требует ручной реализации.


Настройки, влияющие на поведение тач-жестов

1. closeWith

Определяет способы закрытия уведомления.

new Noty({
  text: 'Уведомление',
  closeWith: ['click', 'button']
}).show();

Хотя свайпы не указываются явно, они активны по умолчанию на мобильных устройствах.


2. timeout

Автоматическое закрытие может конфликтовать с жестами.

timeout: false

Отключение таймера даёт пользователю больше времени для взаимодействия.


3. animation

Анимации влияют на восприятие жестов.

animation: {
  open: 'animated fadeIn',
  close: 'animated fadeOut'
}

При использовании свайпов желательно избегать слишком долгих анимаций закрытия.


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

Порог срабатывания

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

Типичное значение: 80–120 пикселей.


Визуальная обратная связь

Во время свайпа Noty сдвигает уведомление вслед за пальцем. Это создаёт ощущение «физического» взаимодействия.

Дополнительно можно:

  • уменьшать прозрачность при удалении
  • добавлять эффект «затухания»

Ограничение направления

Чаще всего используется горизонтальный свайп:

  • влево — закрытие
  • вправо — закрытие

Вертикальные жесты обычно игнорируются, чтобы не конфликтовать с прокруткой страницы.


Кастомизация тач-поведения

Хотя Noty не предоставляет прямого API для настройки touch-событий, возможно вмешательство через DOM.

Получение элемента уведомления

let n = new Noty({ text: 'Пример' }).show();

n.on('afterShow', function() {
  let el = n.barDom;
  
  el.addEventListener('touchstart', customHandler);
});

Пример: ограничение свайпа только влево

el.addEventListener('touchmove', (e) => {
  let diff = e.touches[0].clientX - startX;

  if (diff < 0) {
    el.style.transform = `translateX(${diff}px)`;
  }
});

Обработка множественных касаний

Noty ориентирован на одиночные касания (single touch). При наличии нескольких точек касания:

  • события могут игнорироваться
  • возможны некорректные вычисления смещения

Рекомендуется фильтровать:

if (e.touches.length > 1) return;

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

iOS Safari

  • может добавлять инерцию скролла
  • требует preventDefault() в некоторых случаях

Android Chrome

  • более предсказуемое поведение touch-событий
  • поддержка пассивных слушателей (passive: true)

Использование passive listeners

Для повышения производительности:

element.addEventListener('touchmove', handler, { passive: true });

Однако:

  • нельзя вызывать preventDefault()
  • подходит только если не требуется блокировка скролла

Предотвращение конфликтов с прокруткой

При вертикальном скролле страницы возможны ложные срабатывания.

Решение:

  • анализировать угол движения
  • игнорировать жесты с преобладанием вертикального смещения
let diffX = Math.abs(currentX - startX);
let diffY = Math.abs(currentY - startY);

if (diffY > diffX) {
  // считаем это скроллом, а не свайпом
  return;
}

Интеграция с Pointer Events

Современная альтернатива touch-событиям — Pointer Events:

  • pointerdown
  • pointermove
  • pointerup

Преимущества:

  • единый API для мыши, пера и касаний
  • упрощённая логика

Noty по умолчанию использует классические touch-события, но возможно расширение:

element.addEventListener('pointerdown', handler);

Управление состоянием уведомления при жестах

Во время взаимодействия важно отслеживать состояние:

  • isDragging
  • startPosition
  • currentPosition

Это предотвращает:

  • резкие скачки
  • конфликт анимаций

Производительность

Частые события touchmove могут нагружать интерфейс.

Оптимизации:

  • использовать requestAnimationFrame
  • минимизировать DOM-операции
  • не вызывать перерасчёт layout

Пример:

let ticking = false;

element.addEventListener('touchmove', (e) => {
  if (!ticking) {
    requestAnimationFrame(() => {
      updatePosition(e);
      ticking = false;
    });
    ticking = true;
  }
});

Ограничения и подводные камни

  • отсутствие встроенной настройки чувствительности свайпа
  • сложность кастомизации без вмешательства в DOM
  • возможные конфликты с другими gesture-библиотеками (например, Hammer.js)

Практические рекомендации

  • отключать автоматическое закрытие при активных жестах
  • избегать сложных анимаций
  • тестировать на реальных устройствах
  • учитывать различия между iOS и Android
  • не перегружать уведомления интерактивностью

Расширение функциональности

Для сложных сценариев:

  • интеграция с gesture-библиотеками
  • создание собственных обёрток над Noty
  • добавление кастомных состояний (например, «частично сдвинутое уведомление»)

Это позволяет реализовать:

  • подтверждение удаления
  • действия по свайпу (аналогично мобильным почтовым клиентам)
  • многоступенчатые жесты