Элегантная реализация Long Press обработчика с помощью CSS анимации

от автора

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

▎Зачем нужен Long Press?

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

▎Стандартное решение

Реализация обработчиков долгого и короткого нажатия на чистом JavaScript будет выглядеть примерно следующим образом:

/* HTML */ <button id="btn">Click / Long Press</button>
/* JavaScript */ const btn = document.getElementById('btn'); const clickHandler = () => console.log('Сlick Handler'); const longPressHandler = () => console.log('Long Press Handler');  let timerId, longPressed  btn.onmousedown = () => {   longPressed = false   timerId = setTimeout(() => {     longPressed = true     longPressHandler();   }, 200); }  btn.onclick = () => {   if (!longPressed) clickHandler();   clearTimeout(timerId); }  btn.onmouseleave = () => {   clearTimeout(timerId); }

Демонстрация на CodePen

Как мы видим, код достаточно громоздкий; необходимо использование таймера и глобальных переменных. Также нужно учитывать эффект, когда пользователь нажал на элемент, а отпустил его вне границ — такое поведение не должно вызывать ни один из наших обработчиков. Здесь это отслеживается с помощью слушателя mouseleave.

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

▎Универсальное решение

Давайте рассмотрим, как мы можем реализовать обработчики короткого и длинного нажатия только с помощью CSS:

/* CSS */ #btn {   transition: background-color 1s 200ms; /* animation for long press */ }  #btn:active {   animation-name: interruptClick;   animation-delay: 200ms;   animation-fill-mode: forwards;   background-color: PaleTurquoise; /* styles for long press */ }  #btn:not(:hover){   animation-play-state: paused; }  @keyframes interruptClick {   to {     pointer-events: none;   } }
/* HTML */ <button id="btn">Click / Long Press</button>
/* JavaScript */ const btn = document.getElementById('btn');  btn.onclick = () => console.log('Сlick Handler');  btn.onanimationend = () => console.log('Long Press Handler');

Демонстрация на CodePen

Здесь мы видим, что логика определения долгого и короткого нажатия реализована полностью на CSS. С помощью JavaScript мы только устанавливаем слушателей. При долгом нажатии будет применена отдельная анимация стилизации кнопки (transition: background-color).

▎Как это работает?

1. CSS-анимация для реализации обработчиков:

:active: Этот псевдокласс позволяет применять свойства анимации только в момент удержания кнопки.

animation-name: Определяем @keyframes анимацию с одним ключевым кадром.

pointer-events: Ключевой кадр содержит свойство, управляющее тем, как элемент реагирует на события указателя (например, клики мышью). Клик считается завершенным, когда происходит и нажатие, и отпускание кнопки мыши на одном и том же элементе. Мы используем это свойство со значением “none”, чтобы предотвратить событие клика.

animation-delay: Анимация начинается через 200 миллисекунд после нажатия; это минимальное время удержания, необходимое для его определения как длительного.

animation-fill-mode: Время продолжительности анимации не указано, но благодаря значению “forwards” все свойства ключевого кадра будут оставаться активными до окончания удержания.

:not(:hover): Если пользователь нажал на кнопку, а затем отпустил за её границами, то анимация interruptClick будет остановлена с помощью свойства animation-play-state: paused, и ни один из обработчиков не будет вызван.

2. JavaScript слушатели:

onclick: Этот слушатель соответствует короткому нажатию.

onanimationend: Этот слушатель соответствует поведению долгого нажатия и срабатывает, когда заканчивается анимация interruptClick.

▎Преимущества данного подхода

• Универсальность: Все визуальные эффекты при длинном нажатии можно реализовать только с помощью CSS.

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

• Эффективность: Использование CSS-анимаций позволяет избежать лишних вычислений в JavaScript, что может улучшить производительность.

• Чистота кода: Код остается чистым и легко читаемым.

▎Заключение

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

Я протестировал это решение в нескольких браузерах, на компьютере и мобильном устройстве. Перед использованием кода в продакшене рекомендую провести дополнительное тестирование.


ссылка на оригинал статьи https://habr.com/ru/articles/860704/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *