Trước đây, việc trỏ vào những thông tin trên web vốn rất đơn giản. Bạn có chuột, bạn đã di chuyển nó đơn giản, đôi khi bạn chỉ cần nhấn vào các nút. Mọi thứ không phải là chuột được mô phỏng như một trò chơi và các nhà phát triển biết chính xác cần tin tưởng vào điều gì.
Tuy nhiên, đơn giản không nhất thiết có nghĩa là tốt. Theo thời gian, sản phẩm này ngày càng quan trọng là không phải mọi thứ đều là (hoặc giả vờ) là chuột: bạn có thể có bút cảm ứng áp lực và nhận biết nghiêng, cho sự tự do sáng tạo đáng kinh ngạc; bạn có thể sử dụng ngón tay, nên tất cả những gì bạn cần là thiết bị và bàn tay; và này, tại sao không dùng nhiều hơn một ngón tay khi đang ở đó?
Chúng tôi đã có các sự kiện chạm để giúp chúng tôi làm việc đó, nhưng chúng là một API hoàn toàn riêng biệt cho thao tác chạm, buộc bạn phải lập trình hai mô hình sự kiện riêng biệt nếu bạn muốn hỗ trợ cả chuột và thao tác chạm. Chrome 55 đi kèm với tiêu chuẩn mới hơn giúp hợp nhất cả hai mô hình: sự kiện con trỏ.
Mô hình sự kiện đơn lẻ
Sự kiện con trỏ hợp nhất mô hình nhập bằng con trỏ cho trình duyệt, kết nối cảm ứng, bút và chuột với nhau thành một nhóm sự kiện duy nhất. Ví dụ:
document.addEventListener('pointermove',
ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
ev => console.log('The pointer is now over foo.'));
Sau đây là danh sách tất cả sự kiện hiện có. Danh sách này khá quen thuộc nếu bạn bạn đã quen thuộc với sự kiện chuột:
pointerover
|
Con trỏ đã nhập vào hộp giới hạn của phần tử.
Thao tác này xảy ra ngay lập tức đối với các thiết bị hỗ trợ tính năng di chuột hoặc trước khi
Sự kiện pointerdown cho các thiết bị không hoạt động.
|
pointerenter
|
Tương tự như pointerover , nhưng không tạo bong bóng trò chuyện và tên người dùng
các thành phần con cháu khác nhau.
Thông tin chi tiết về thông số kỹ thuật.
|
pointerdown
|
Con trỏ đã chuyển sang trạng thái nút đang hoạt động, với một nút là nhấn hoặc tiếp xúc được thiết lập, tuỳ thuộc vào ngữ nghĩa của thiết bị đầu vào. |
pointermove
|
Con trỏ đã thay đổi vị trí. |
pointerup
|
Con trỏ đã rời khỏi trạng thái nút đang hoạt động. |
pointercancel
|
Đã xảy ra lỗi nên con trỏ rất ít khả năng sẽ phát ra bất kỳ sự kiện khác. Điều này có nghĩa là bạn nên huỷ mọi thao tác đang diễn ra và tiếp tục trở về trạng thái đầu vào bình thường. |
pointerout
|
Con trỏ đã rời khỏi hộp giới hạn của phần tử hoặc màn hình. Ngoài ra, sau một
pointerup , nếu thiết bị không hỗ trợ tính năng di chuột.
|
pointerleave
|
Tương tự như pointerout , nhưng không tạo bong bóng trò chuyện và tên người dùng
các thành phần con cháu khác nhau.
Thông tin chi tiết về thông số kỹ thuật.
|
gotpointercapture
|
Phần tử đã nhận được người chụp con trỏ. |
lostpointercapture
|
Con trỏ đang được chụp đã bị phát hành. |
Nhiều loại dữ liệu đầu vào
Nói chung, Sự kiện con trỏ cho phép bạn viết mã theo cách không phụ thuộc vào đầu vào,
mà không cần đăng ký trình xử lý sự kiện riêng biệt cho các thiết bị đầu vào khác nhau.
Tất nhiên, bạn vẫn cần chú ý đến sự khác biệt giữa các loại dữ liệu đầu vào, chẳng hạn như
áp dụng khái niệm di chuột. Nếu muốn phân biệt các loại thiết bị đầu vào khác nhau, bạn có thể cung cấp
riêng mã/chức năng cho các đầu vào khác nhau – tuy nhiên bạn có thể làm như vậy từ
trong cùng một trình xử lý sự kiện bằng cách sử dụng thuộc tính pointerType
của
PointerEvent
. Ví dụ: nếu đang lập trình một ngăn điều hướng bên, bạn có thể
có logic sau trên sự kiện 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;
}
Thao tác mặc định
Trong các trình duyệt hỗ trợ thao tác chạm, một số cử chỉ nhất định được sử dụng để cuộn, thu phóng hoặc làm mới trang.
Trong trường hợp sự kiện chạm, bạn vẫn sẽ nhận được các sự kiện khi các sự kiện mặc định này
đang diễn ra – ví dụ: touchmove
sẽ vẫn được kích hoạt trong khi người dùng đang cuộn.
Với sự kiện con trỏ, bất cứ khi nào một hành động mặc định như cuộn hoặc thu phóng được kích hoạt,
bạn sẽ nhận được một sự kiện pointercancel
để cho bạn biết rằng trình duyệt đã lấy
quyền điều khiển con trỏ. Ví dụ:
document.addEventListener('pointercancel',
ev => console.log('Go home, the browser is in charge now.'));
Tốc độ tích hợp sẵn: Mô hình này cho phép có hiệu suất tốt hơn theo mặc định, so với các sự kiện chạm, trong đó bạn cần sử dụng trình nghe sự kiện thụ động để đạt được cùng mức độ phản hồi.
Bạn có thể ngăn trình duyệt nắm quyền kiểm soát bằng
touch-action
thuộc tính CSS. Nếu bạn đặt chính sách này thành none
trên một phần tử, tất cả các tuỳ chọn quảng cáo sẽ bị tắt
các hành động do trình duyệt xác định đã bắt đầu trên phần tử đó. Tuy nhiên, có một số
các giá trị khác để kiểm soát chi tiết hơn, chẳng hạn như pan-x
, để cho phép
trình duyệt để phản ứng với chuyển động trên trục x nhưng không phản ứng với trục y. Chrome 55
hỗ trợ các giá trị sau:
auto
|
Mặc định; trình duyệt có thể thực hiện bất kỳ hành động mặc định nào. |
none
|
Trình duyệt không được phép thực hiện bất kỳ hành động mặc định nào. |
pan-x
|
Trình duyệt chỉ được phép thực hiện thao tác mặc định là cuộn theo chiều ngang. |
pan-y
|
Trình duyệt chỉ được phép thực hiện thao tác mặc định là cuộn theo chiều dọc. |
pan-left
|
Trình duyệt chỉ được phép thực hiện thao tác mặc định cuộn theo chiều ngang, và chỉ để xoay trang sang trái. |
pan-right
|
Trình duyệt chỉ được phép thực hiện thao tác mặc định cuộn theo chiều ngang, và chỉ để xoay trang sang phải. |
pan-up
|
Trình duyệt chỉ được phép thực hiện thao tác mặc định cuộn theo chiều dọc. và chỉ di chuyển trang lên trên. |
pan-down
|
Trình duyệt chỉ được phép thực hiện thao tác mặc định cuộn theo chiều dọc. và chỉ dùng để di chuyển trang xuống. |
manipulation
|
Trình duyệt chỉ được phép thực hiện các thao tác cuộn và thu phóng. |
Chụp con trỏ
Bạn đã từng dành một giờ khó chịu để gỡ lỗi mouseup
bị hỏng
cho đến khi bạn nhận ra rằng đó là do người dùng thả nút
nằm ngoài mục tiêu nhấp chuột của bạn? Bạn không thấy đúng không? Được rồi, có lẽ chỉ có một mình tôi.
Tuy nhiên, cho đến nay vẫn chưa có cách thực sự hiệu quả để giải quyết vấn đề này. Chắc chắn rồi,
bạn có thể thiết lập trình xử lý mouseup
trên tài liệu này và lưu một số trạng thái trên
ứng dụng của bạn để theo dõi mọi thứ. Đó không phải là giải pháp sạch nhất,
đặc biệt nếu bạn đang tạo thành phần web và cố gắng giữ cho mọi thứ tốt đẹp
bị tách biệt.
Với sự kiện con trỏ, giải pháp này tốt hơn nhiều: bạn có thể thu thập con trỏ,
để bạn chắc chắn nhận được sự kiện pointerup
đó (hoặc bất kỳ sự kiện nào khác khó nắm bắt
bạn bè).
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!'));
Hỗ trợ trình duyệt
Tại thời điểm viết bài này, Sự kiện con trỏ được hỗ trợ trong Internet Explorer 11, Microsoft Edge, Chrome và Opera và được hỗ trợ một phần trong Firefox. Bạn có thể hãy tìm danh sách đã cập nhật tại caniuse.com.
Bạn có thể sử dụng polyfill Sự kiện con trỏ cho bổ sung thông tin còn thiếu. Ngoài ra, việc kiểm tra khả năng hỗ trợ của trình duyệt trong thời gian chạy là đơn giản:
if (window.PointerEvent) {
// Yay, we can use pointer events!
} else {
// Back to mouse and touch events, I guess.
}
Sự kiện con trỏ là một ứng cử viên tuyệt vời cho tính năng nâng cao tiến bộ: chỉ cần
sửa đổi phương thức khởi chạy để kiểm tra ở trên, thêm sự kiện con trỏ
trong khối if
và di chuyển trình xử lý sự kiện chuột/chạm của bạn sang
Khối else
.
Vì vậy, hãy dùng thử và cho chúng tôi biết bạn nghĩ gì!