Pointer Events
В останньому відео про події миші я побіжно розглянув і Pointer Events, які стали логічним продовженням розвитку Mouse Events. Сьогодні ж хочу подивитися до них дещо детальніше (але не дуже).
Тривалий час, аби підтримувати пристрої з дотиком, нам доводилось користуватися одночасно двома різними інтерфейсами: Mouse Events та Touch Events. Це привносило додаткову складність та могло призводити до прикрих багів та халеп, найпростішою з яких було просто забути продублювати логіку.
І ось у 2013 році Microsoft, на диво для всіх, зробила щось неочікуване: створила Pointer Events — єдину модель взаємодій для всіх типів вказівників. Згодом її стандартизували у W3C, а нині її підтримують усі сучасні браузери, включно з Safari.
Що таке Pointer Events
Pointer Events — це уніфікована модель DOM-подій, у якій поняття "вказівник" (pointer) охоплює мишу, дотик та стилус. Замість трьох різних наборів подій ми маємо одну логічну систему:
element.addEventListener('pointerdown', e => {
console.log(e.pointerType, e.pressure);
});Події
pointerdown, pointermove, pointerup, pointerenter, pointerleave працюють однаково для всіх пристроїв.У кожної взаємодії є власний
pointerId (щоб відстежувати кілька дотиків), pointerType ("mouse" | "touch" | "pen"), pressure (сила натиску), а також координати, кнопки, модифікатори — поєднуючи класичні MouseEvent та специфічні для дотиків властивості.click, до речі, лишили як універсальну подію.Один код — усі пристрої
Основна перевага Pointer Events — універсальність. Можна реалізувати drag’n’drop, малювання або будь-який інший інтерактив без окремих костилів для миші та дотиків.
Якщо користувач натискає пальцем, викликається
pointerdown; якщо мишею — теж pointerdown.Для мультитачу кожен дотик має свій
pointerId, що дозволяє легко опрацьовувати складні жести чи визначати кількість активних точок.Крім того, Pointer Events підтримують так званий pointer capture — механізм, який дозволяє "прив’язати" вказівник до елемента навіть після того, як курсор або палець вийде за його межі.
element.setPointerCapture(e.pointerId);
Тонке налаштування
Бравзери, що підтримують Pointer Events, усе ще генерують події миші (
mousedown, mouseup, click) для сумісності.Тобто при торканні кнопки може спрацювати і
pointerdown, і mousedown. Якщо ви вже перейшли на нову модель, це може призвести до непотрібного дублювання.Розв’язання просте: якщо викликати
event.preventDefault() на pointerdown, браузер не згенерує певні сумісні мишачі події (принаймні для touch і pen). Але це стосується лише "контактних" подій на кшталт mousedown. Події штибу mousemove чи mouseenter в такий спосіб, на жаль, не блокуються.Також системну взаємодію на кшталт zoom та panning через JS взагалі неможливо перехопити, лише за допомогою CSS:
canvas {
touch-action: none; /* вимикає зум і прокрутку */
}Mouse vs Pointer — що вибрати?
Якщо ваш застосунок орієнтований лише на десктоп — старі події миші цілком ок. Вони простіші, і багато бібліотек досі працюють саме з ними.
Якщо ж ваш продукт має мобільну авдиторію, або ви працюєте з Canvas, жестами чи стилусом — Pointer Events однозначно кращі.
Проте, якщо у вас є специфічні кейси (наприклад, HTML5 Drag’n’Drop), де Pointer Events ще не інтегровані — можна тимчасово поєднати обидві моделі.
Щодо drag'n'drop — щоб не заглиблюватись, гляньте в спеку, вони побудовані повністю на MouseEvents,
dragstart стартує після звʼязки mousedown + mousemove.Підсумок
Не варто сприймати Pointer Events як просто "ще один API". Це логічна еволюція, що прибирає штучний поділ між пристроями й робить взаємодію у вебі дійсно універсальною.
Колись ми писали купу різних обробників для однієї кнопки, а тепер достатньо одного —
pointerdown.Як на мене, PointerEvents є одним з тих прикладів, коли розвиток специфікації не намагається вигадати щось кардинально нове, а поступово й логічно надбудовує нові можливості, залишаючи при цьому старі досі актуальними.
Що почитати:
📖 W3C Pointer Events Level 3
📖 MDN: Pointer Events
📖 Chrome Developers Blog: "Pointing the way forward"
@babichdev