Menunjukkan arah ke depan

Sérgio Gomes

Menunjuk sesuatu di web dulunya mudah. Anda memiliki mouse, Anda menggerakkannya, terkadang Anda menekan tombol, dan selesai. Semua yang bukan mouse di-emulasi sebagai mouse, dan developer tahu persis apa yang harus diandalkan.

Namun, sederhana bukan berarti baik. Seiring waktu, semakin penting agar tidak semua perangkat (atau berpura-pura menjadi) mouse: Anda dapat memiliki pena yang sensitif terhadap tekanan dan kemiringan, untuk kebebasan berkreasi yang luar biasa; Anda dapat menggunakan jari, sehingga yang Anda butuhkan hanyalah perangkat dan tangan Anda; dan, mengapa tidak menggunakan lebih dari satu jari saat melakukannya?

Kami telah memiliki peristiwa sentuh selama beberapa waktu untuk membantu kami, tetapi API tersebut sepenuhnya terpisah khusus untuk sentuh, sehingga Anda harus membuat kode dua model peristiwa terpisah jika ingin mendukung mouse dan sentuh. Chrome 55 dilengkapi dengan standar yang lebih baru yang menyatukan kedua model: peristiwa pointer.

Satu model peristiwa

Peristiwa pointer menyatukan model input pointer untuk browser, yang menggabungkan 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 adalah daftar semua peristiwa yang tersedia, yang akan terlihat cukup familier jika Anda sudah terbiasa dengan peristiwa mouse:

pointerover Pointer telah memasuki kotak pembatas elemen. Hal ini terjadi segera untuk perangkat yang mendukung pengarahan kursor, atau sebelum peristiwa pointerdown untuk perangkat yang tidak mendukungnya.
pointerenter Serupa dengan pointerover, tetapi tidak mengapung 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 Posisi pointer telah berubah.
pointerup Pointer telah keluar dari status tombol aktif.
pointercancel Terjadi sesuatu yang berarti pointer tidak akan memunculkan peristiwa lagi. Artinya, Anda harus membatalkan tindakan yang sedang berlangsung dan kembali ke status input netral.
pointerout Pointer telah keluar dari kotak pembatas elemen atau layar. Juga setelah pointerup, jika perangkat tidak mendukung pengarahan kursor.
pointerleave Serupa dengan pointerout, tetapi tidak mengapung dan menangani turunan secara berbeda. Detail tentang spesifikasi.
gotpointercapture Elemen telah menerima rekaman pointer.
lostpointercapture Pointer yang direkam telah dilepaskan.

Berbagai jenis input

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 tetap harus memperhatikan perbedaan antara jenis input, seperti apakah konsep pengarahan kursor berlaku. Jika ingin membedakan jenis perangkat input yang berbeda – mungkin untuk menyediakan 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 pada 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 sentuh, gestur tertentu digunakan untuk men-scroll, memperbesar, atau memuat ulang halaman. 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 Anda bahwa browser telah mengambil 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 dengan peristiwa sentuh, yang mengharuskan Anda menggunakan pemroses peristiwa pasif untuk mencapai tingkat responsivitas yang sama.

Anda dapat menghentikan browser agar tidak mengambil kontrol dengan properti CSS touch-action. Menetapkan ke none pada elemen akan menonaktifkan semua tindakan yang ditentukan browser yang dimulai di 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 untuk menggeser halaman ke kiri.
pan-right Browser hanya diizinkan untuk melakukan tindakan default scroll horizontal, dan hanya untuk 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 untuk melakukan tindakan scroll dan zoom.

Rekaman pointer

Pernahkah Anda menghabiskan waktu satu jam yang melelahkan untuk men-debug peristiwa mouseup yang rusak, hingga Anda menyadari bahwa hal itu karena pengguna melepaskan tombol di luar target klik Anda? Tidak? Oke, mungkin hanya saya.

Namun, hingga saat ini belum ada cara yang benar-benar baik untuk mengatasi masalah ini. Tentu saja, Anda dapat menyiapkan pengendali mouseup pada dokumen, dan menyimpan beberapa status di aplikasi untuk melacak berbagai hal. Namun, ini bukan solusi yang paling bersih, terutama jika Anda mem-build komponen web dan mencoba menjaga semuanya tetap rapi dan terisolasi.

Dengan peristiwa pointer, Anda akan mendapatkan solusi yang jauh lebih baik: Anda dapat menangkap pointer, sehingga Anda pasti mendapatkan peristiwa pointerup tersebut (atau teman-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, 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 polyfill Peristiwa Pointer untuk mengisi kesenjangan. Atau, memeriksa dukungan browser saat runtime sangat 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 di blok if, dan pindahkan pengendali peristiwa mouse/sentuh ke blok else.

Jadi, silakan coba dan beri tahu kami pendapat Anda.