Долгое нажатие

В Zepto.js обработка событий максимально приближена к подходу jQuery, но при этом библиотека остаётся лёгкой и минималистичной. Долгое нажатие — это событие, которое возникает, когда пользователь удерживает палец или кнопку мыши на элементе в течение заданного времени. В стандартном API браузера прямого события longpress нет, поэтому его необходимо реализовать с помощью комбинации событий touchstart, touchend, mousedown и mouseup.


Основная идея реализации

Долгое нажатие фиксируется через запуск таймера при начале взаимодействия с элементом и его отмену при прекращении действия:

  1. Запуск таймера: при touchstart или mousedown создаётся setTimeout, который через заданное время (обычно 500–1000 мс) вызывает callback.
  2. Отмена таймера: при touchend, mouseup или mouseleave таймер очищается функцией clearTimeout.
  3. Флаг срабатывания: часто используется булева переменная, чтобы определить, произошло ли уже срабатывание долгого нажатия и не триггерить обычный клик.

Пример базового подхода:

var longPressDuration = 800; // время удержания в миллисекундах

$.fn.longPress = function(callback) {
    return this.each(function() {
        var timer;
        var fired = false;
        
        $(this).on('touchstart mousedown', function(e) {
            fired = false;
            timer = setTimeout(function() {
                fired = true;
                callback.call(e.target, e);
            }, longPressDuration);
        });
        
        $(this).on('touchend mouseup mouseleave', function() {
            clearTimeout(timer);
        });
    });
};

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

  • Объединение touch и mouse событий позволяет покрыть как сенсорные устройства, так и мышь.
  • fired предотвращает повторное срабатывание callback при нескольких событиях.
  • mouseleave нужен, чтобы длинное нажатие не срабатывало, если пользователь случайно уводит курсор или палец за пределы элемента.

Настройка времени срабатывания

Важной частью UX является чувствительность к длительности удержания. Значение longPressDuration может варьироваться:

  • Короткое удержание (500–700 мс): быстро реагирует, подходит для мобильных интерфейсов с жестами.
  • Стандартное (800–1000 мс): универсальный вариант для большинства веб-приложений.
  • Длительное (1200–1500 мс): используется для предотвращения случайного срабатывания, например, в административных панелях.

Для удобства длительность можно передавать через опции:

$.fn.longPress = function(callback, duration) {
    var longPressDuration = duration || 800;
    return this.each(function() {
        var timer;
        var fired = false;
        
        $(this).on('touchstart mousedown', function(e) {
            fired = false;
            timer = setTimeout(function() {
                fired = true;
                callback.call(e.target, e);
            }, longPressDuration);
        });
        
        $(this).on('touchend mouseup mouseleave', function() {
            clearTimeout(timer);
        });
    });
};

Обработка предотвращения конфликта с кликом

Если на элемент навешаны и обычный click, и longPress, необходимо различать короткий клик и удержание. Для этого используют дополнительный флаг:

$(element).longPress(function(e) {
    console.log('Долгое нажатие сработало');
}).on('click', function(e) {
    if ($(this).data('longPressed')) {
        e.preventDefault();
        $(this).data('longPressed', false);
    } else {
        console.log('Обычный клик');
    }
});

Внутри longPress callback перед срабатыванием можно устанавливать:

$(this).data('longPressed', true);

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

  1. События touch vs mouse: на сенсорных устройствах часто генерируются оба события, поэтому важно корректно очищать таймер и предотвращать двойное срабатывание.
  2. scroll и swipe: при движении пальца (touchmove) таймер лучше отменять, чтобы удержание не срабатывало во время прокрутки.
  3. Prevent default: иногда для корректного UX нужно добавить e.preventDefault() при touchstart, чтобы предотвратить нежелательные события браузера.
$(this).on('touchstart', function(e) {
    e.preventDefault(); // блокирует нежелательные эффекты, например, выделение текста
});

Расширенные возможности

  • Поворот или мульти-тач: при необходимости можно отслеживать количество пальцев и игнорировать удержание, если пользователь использует более одного касания.
  • Интерактивные элементы: можно включить визуальный отклик (подсветку или анимацию) во время удержания с помощью CSS-классов.
  • Универсальная библиотека: на основе Zepto можно создать плагин, который обрабатывает длинное нажатие для любых элементов и событий с опциональными параметрами: duration, preventDefault, onCancel.

Пример с визуальной подсветкой:

$(element).on('touchstart mousedown', function() {
    $(this).addClass('pressing');
}).on('touchend mouseup mouseleave', function() {
    $(this).removeClass('pressing');
});

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

  • Использовать делегирование событий для большого числа элементов вместо навешивания обработчиков на каждый.
  • Очистка таймера обязательно при любых событиях окончания взаимодействия, чтобы избежать утечек памяти.
  • Минимизировать использование preventDefault, чтобы не блокировать стандартные функции браузера без необходимости.

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