Menunjukkan arah ke depan

Sérgio Gomes

Mengarahkan ke hal-hal di web dulunya mudah. Anda memiliki {i>mouse<i}, Anda memindahkannya, kadang-kadang Anda menekan tombol, dan itu dia. Segala sesuatu yang bukan mouse diemulasikan sebagai satu, dan developer tahu persis apa yang harus diandalkan.

Meskipun sederhana, itu tidak berarti bagus. Seiring waktu, menjadi semakin penting bahwa tidak semuanya (atau berpura-pura seperti) tikus: Anda bisa saja memiliki pena yang sensitif terhadap tekanan dan sadar kemiringan, untuk kebebasan kreatif yang luar biasa; Anda dapat menggunakan jari, jadi yang Anda butuhkan hanyalah perangkat dan tangan Anda; dan, mengapa tidak menggunakan lebih dari satu jari saat Anda melakukannya?

Kami sudah lama memiliki peristiwa sentuh untuk membantu melakukannya, tetapi ini adalah API yang sepenuhnya terpisah khusus untuk sentuhan, yang memaksa Anda membuat kode dua model peristiwa terpisah jika Anda ingin mendukung mouse dan sentuh. Chrome 55 dikirimkan dengan standar lebih baru yang menggabungkan kedua model: peristiwa pointer.

Model peristiwa tunggal

Peristiwa pointer menyatukan model input pointer untuk browser, sehingga menyatukan sentuhan, pena, dan mouse ke dalam satu kumpulan peristiwa. Contoh:

document.addEventListener('pointermove',
    ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
    ev => console.log('The pointer is now over foo.'));

Berikut daftar semua peristiwa yang tersedia, yang akan terlihat cukup familier jika Anda familier dengan peristiwa mouse:

pointerover Pointer telah memasuki kotak pembatas elemen. Hal ini akan segera terjadi untuk perangkat yang mendukung pengarahan kursor, atau sebelum peristiwa pointerdown untuk perangkat yang tidak mendukungnya.
pointerenter Serupa dengan pointerover, tetapi tidak menggelembung dan menangani turunan secara berbeda. Detail tentang spesifikasi.
pointerdown Pointer telah memasuki status tombol aktif, dengan tombol ditekan atau kontak dibuat, bergantung pada semantik perangkat input.
pointermove Pointer telah berubah posisi.
pointerup Pointer telah meninggalkan status tombol aktif.
pointercancel Sesuatu telah terjadi, yang berarti pointer tidak mungkin memunculkan peristiwa lagi. Artinya, Anda harus membatalkan semua tindakan yang sedang berlangsung dan kembali ke status input netral.
pointerout Pointer telah meninggalkan kotak pembatas elemen atau layar. Juga setelah pointerup, jika perangkat tidak mendukung pengarahan kursor.
pointerleave Serupa dengan pointerout, tetapi tidak menggelembung dan menangani turunan secara berbeda. Detail tentang spesifikasi.
gotpointercapture Elemen telah menerima tangkapan pointer.
lostpointercapture Pointer yang diambil telah dirilis.

Jenis input yang berbeda

Umumnya, Peristiwa Pointer memungkinkan Anda menulis kode dengan cara yang tidak bergantung pada input, tanpa perlu mendaftarkan pengendali peristiwa terpisah untuk perangkat input yang berbeda. Tentu saja, Anda masih perlu memperhatikan perbedaan antara jenis input, seperti apakah konsep pengarahan kursor berlaku atau tidak. Jika Anda ingin membedakan berbagai jenis perangkat input – mungkin untuk memberikan kode/fungsi terpisah untuk input yang berbeda – Anda dapat melakukannya dari dalam pengendali peristiwa yang sama menggunakan properti pointerType dari antarmuka PointerEvent. Misalnya, jika Anda membuat kode panel navigasi samping, Anda dapat memiliki logika berikut di peristiwa pointermove:

switch(ev.pointerType) {
    case 'mouse':
    // Do nothing.
    break;
    case 'touch':
    // Allow drag gesture.
    break;
    case 'pen':
    // Also allow drag gesture.
    break;
    default:
    // Getting an empty string means the browser doesn't know
    // what device type it is. Let's assume mouse and do nothing.
    break;
}

Tindakan default

Di browser yang mendukung sentuhan, gestur tertentu digunakan untuk membuat halaman men-scroll, memperbesar/memperkecil, atau memuat ulang. Dalam kasus peristiwa sentuh, Anda akan tetap menerima peristiwa saat tindakan default ini berlangsung – misalnya, touchmove akan tetap diaktifkan saat pengguna men-scroll.

Dengan peristiwa pointer, setiap kali tindakan default seperti scroll atau zoom dipicu, Anda akan mendapatkan peristiwa pointercancel, untuk memberi tahu bahwa browser telah mengambil alih kontrol pointer. Contoh:

document.addEventListener('pointercancel',
    ev => console.log('Go home, the browser is in charge now.'));

Kecepatan bawaan: Model ini memungkinkan performa yang lebih baik secara default, dibandingkan peristiwa sentuh, saat Anda perlu menggunakan pemroses peristiwa pasif untuk mencapai tingkat responsivitas yang sama.

Anda dapat menghentikan browser mengambil kontrol dengan properti CSS touch-action. Menyetelnya ke none pada suatu elemen akan menonaktifkan semua tindakan yang ditentukan browser yang dimulai pada elemen tersebut. Namun, ada sejumlah nilai lain untuk kontrol yang lebih terperinci, seperti pan-x, untuk memungkinkan browser bereaksi terhadap gerakan pada sumbu x, tetapi tidak pada sumbu y. Chrome 55 mendukung nilai berikut:

auto Default; browser dapat melakukan tindakan default apa pun.
none Browser tidak diizinkan untuk melakukan tindakan default apa pun.
pan-x Browser hanya diizinkan untuk melakukan tindakan default scroll horizontal.
pan-y Browser hanya diizinkan untuk melakukan tindakan default scroll vertikal.
pan-left Browser hanya diizinkan untuk melakukan tindakan default scroll horizontal, dan hanya menggeser halaman ke kiri.
pan-right Browser hanya diizinkan untuk melakukan tindakan default scroll horizontal, dan hanya menggeser halaman ke kanan.
pan-up Browser hanya diizinkan untuk melakukan tindakan default scroll vertikal, dan hanya untuk menggeser halaman ke atas.
pan-down Browser hanya diizinkan untuk melakukan tindakan default scroll vertikal, dan hanya untuk menggeser halaman ke bawah.
manipulation Browser hanya diizinkan melakukan tindakan scroll dan zoom.

Rekaman pointer

Pernah menghabiskan waktu berjam-jam untuk men-debug peristiwa mouseup yang rusak, sampai Anda menyadari bahwa hal tersebut terjadi karena pengguna melepaskan tombol di luar target klik Anda? Tidak? Oke, mungkin hanya aku.

Namun, sampai saat ini belum ada cara yang benar-benar baik untuk mengatasi masalah ini. Tentu, Anda dapat menyiapkan pengendali mouseup pada dokumen, dan menyimpan beberapa status di aplikasi Anda untuk melacak berbagai hal. Namun, itu bukanlah solusi yang paling baik, terutama jika Anda membuat komponen web dan mencoba menjaga semuanya tetap baik dan terisolasi.

Dengan peristiwa pointer, solusi yang lebih baik akan tersedia: Anda dapat merekam pointer, sehingga Anda yakin untuk mendapatkan peristiwa pointerup tersebut (atau teman lainnya yang sulit dipahami).

const foo = document.querySelector('#foo');
foo.addEventListener('pointerdown', ev => {
    console.log('Button down, capturing!');
    // Every pointer has an ID, which you can read from the event.
    foo.setPointerCapture(ev.pointerId);
});

foo.addEventListener('pointerup', 
    ev => console.log('Button up. Every time!'));

Dukungan browser

Pada saat penulisan ini, Peristiwa Pointer didukung di Internet Explorer 11, Microsoft Edge, Chrome, dan Opera, serta didukung sebagian di Firefox. Anda dapat menemukan daftar terbaru di caniuse.com.

Anda dapat menggunakan Pointer Events polyfill untuk mengisi kekurangan. Selain itu, memeriksa dukungan browser saat runtime dapat dilakukan dengan mudah:

if (window.PointerEvent) {
    // Yay, we can use pointer events!
} else {
    // Back to mouse and touch events, I guess.
}

Peristiwa pointer adalah kandidat yang bagus untuk progressive enhancement: cukup ubah metode inisialisasi untuk melakukan pemeriksaan di atas, tambahkan pengendali peristiwa pointer dalam blok if, dan pindahkan pengendali peristiwa mouse/sentuh ke blok else.

Jadi, cobalah dan sampaikan pendapat Anda!