Wskazywanie rzeczy w internecie było kiedyś proste. Mieliśmy mysz, którą można było przesuwać, czasami naciskać przyciski, i to wszystko. Wszystko, co nie było myszką, było emulowane jako mysz, a deweloperzy wiedzieli dokładnie, na co mogą liczyć.
Prostota nie musi jednak oznaczać jakości. Z czasem coraz większą rolę zaczęły odgrywać urządzenia inne niż mysz: pióra reagujące na nacisk i przechylanie, które zapewniały niesamowitą swobodę twórczą; urządzenia, które można obsługiwać palcami, więc do pracy wystarczyło urządzenie i ręka; a dodatkowo, czemu nie używać więcej niż jednego palca?
Od jakiegoś czasu mamy zdarzenia dotykowe, które pomagają nam w tym zakresie, ale są to zupełnie osobne interfejsy API, przeznaczone do obsługi dotykowych ekranów dotykowych. Jeśli chcesz obsługiwać zarówno mysz, jak i dotykowe ekrany dotykowe, musisz zaprogramować 2 osobne modele zdarzeń. Chrome 55 zawiera nowszy standard, który łączy oba modele: zdarzenia wskaźnika.
Model pojedynczego zdarzenia
Zdarzenia związane z wskaźnikiem unifikują model danych wejściowych wskaźnika w przeglądarce, łącząc w jeden zestaw zdarzeń dane z dotyku, piór i myszy. Na przykład:
document.addEventListener('pointermove',
ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
ev => console.log('The pointer is now over foo.'));
Oto lista wszystkich dostępnych zdarzeń, która powinna wyglądać znajomo, jeśli znasz zdarzenia myszy:
pointerover
|
Wskaźnik wszedł do pudełka ograniczającego element.
Dzieje się tak natychmiast w przypadku urządzeń, które obsługują najechanie kursorem, lub przed zdarzeniempointerdown na urządzeniach, które nie obsługują tej funkcji.
|
pointerenter
|
Podobna do reguły pointerover , ale nie przenosi wartości do góry i różnie sposoby obsługi potomków.
Szczegóły specyfikacji
|
pointerdown
|
Wskaźnik wszedł w stan aktywnego przycisku, w którym albo został naciśnięty przycisk, albo nawiązano kontakt, w zależności od semantyki urządzenia wejściowego. |
pointermove
|
Wskaźnik zmienił pozycję. |
pointerup
|
Wskaźnik opuścił stan aktywnego przycisku. |
pointercancel
|
Coś się stało, co oznacza, że wskaźnik prawdopodobnie nie wyemituje już żadnych zdarzeń. Oznacza to, że należy anulować wszystkie trwające działania i wrócić do neutralnego stanu. |
pointerout
|
wskaźnik opuścił ramkę elementu lub ekranu; Również po pointerup , jeśli urządzenie nie obsługuje funkcji hover.
|
pointerleave
|
Podobna do reguły pointerout , ale nie przenosi wartości do góry i różnie sposoby obsługi potomków.
Szczegóły specyfikacji
|
gotpointercapture
|
Element otrzymał przechwytywanie kursora. |
lostpointercapture
|
Wskaźnik, który był przechwycony, został zwolniony. |
Różne typy danych wejściowych
Ogólnie zdarzenia związane z wskaźnikiem umożliwiają pisanie kodu w sposób niezależny od sposobu wprowadzania danych, bez konieczności rejestrowania oddzielnych metod obsługi zdarzeń dla różnych urządzeń wejściowych.
Nadal musisz jednak pamiętać o różnicach między typami danych wejściowych, np. o tym, czy ma zastosowanie koncepcja najechania kursorem. Jeśli chcesz odróżnić różne typy urządzeń wejściowych (np. aby zapewnić osobny kod lub funkcję dla różnych urządzeń wejściowych), możesz to zrobić w ramach tych samych metod obsługi zdarzeń, używając właściwości pointerType
interfejsu PointerEvent
. Jeśli np. kodujesz boczny panel nawigacyjny, możesz użyć tej logiki w przypadku zdarzenia 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;
}
Działania domyślne
W przeglądarkach z obsługą dotykiem do przewijania, powiększania i odświeżania strony służą określone gesty.
W przypadku zdarzeń dotykowych nadal będziesz otrzymywać zdarzenia, gdy będą wykonywane te domyślne działania – np. zdarzenie touchmove
będzie nadal wywoływane, gdy użytkownik przewija stronę.
W przypadku zdarzeń wskaźnika, gdy zostanie wywołane domyślne działanie, takie jak przewijanie lub powiększanie, otrzymasz zdarzenie pointercancel
, aby poinformować, że przeglądarka przejęła kontrolę nad kursorem. Na przykład:
document.addEventListener('pointercancel',
ev => console.log('Go home, the browser is in charge now.'));
Wbudowana szybkość: ten model zapewnia domyślnie lepszą wydajność w porównaniu ze zdarzeniami dotykowymi, w których przypadku do osiągnięcia takiego samego poziomu szybkości reakcji musisz używać biernych odbiorników zdarzeń.
Możesz uniemożliwić przeglądarce przejęcie kontroli za pomocą właściwości touch-action
w kodzie CSS. Ustawienie tej właściwości na none
spowoduje wyłączenie wszystkich działań określonych przez przeglądarkę, które zostały uruchomione na tym elemencie. Dostępne są jednak inne wartości, które umożliwiają bardziej szczegółowe sterowanie, np. pan-x
, aby umożliwić przeglądarce reagowanie na ruch wzdłuż osi x, ale nie wzdłuż osi y. Chrome 55 obsługuje te wartości:
auto
|
Domyślna. Przeglądarka może wykonać dowolne domyślne działanie. |
none
|
Przeglądarka nie może wykonywać żadnych domyślnych działań. |
pan-x
|
Przeglądarka może wykonać tylko domyślne działanie przewijania w poziomie. |
pan-y
|
Przeglądarka może wykonywać tylko domyślną czynność przewijania w pionie. |
pan-left
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w poziomie i tylko przesuwać stronę w lewo. |
pan-right
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w poziomie i tylko przesuwać stronę w prawo. |
pan-up
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w poziomie i tylko przesuwać stronę w górę. |
pan-down
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w poziomie i tylko przesuwać stronę w dół. |
manipulation
|
Przeglądarka może tylko przewijać i powiększać. |
Wskaźnik
Czy zdarzyło Ci się spędzić godzinę na debugowaniu nieprawidłowego zdarzenia mouseup
, zanim zdasz sobie sprawę, że to dlatego, że użytkownik puścił przycisk poza obszarem docelowym kliknięcia? Nie? OK, może to tylko ja.
Do tej pory nie było jednak dobrego sposobu na rozwiązanie tego problemu. Oczywiście. Możesz skonfigurować w dokumentach mouseup
i zapisz stan aplikacji, aby móc śledzić zmiany. Nie jest to jednak najprostsze rozwiązanie, zwłaszcza jeśli tworzysz komponent internetowy i chcesz zachować wszystko w odseparowaniu.
Zdarzenia związane z wskaźnikiem to znacznie lepsze rozwiązanie: możesz rejestrować ruch kursora, aby mieć pewność, że pointerup
zdarzenie (lub inne z jego ulotnych przyjaciół).
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!'));
Obsługa przeglądarek
W momencie pisania tego artykułu zdarzenia wskaźnika są obsługiwane w Internet Explorerze 11, Microsoft Edge, Chrome i Operze, a w Firefoksie są częściowo obsługiwane. Aktualną listę znajdziesz na stronie caniuse.com.
Do wypełnienia luk możesz użyć wypełnienia wskaźnika zdarzeń. Sprawdzanie obsługi przeglądarki w czasie działania jest proste:
if (window.PointerEvent) {
// Yay, we can use pointer events!
} else {
// Back to mouse and touch events, I guess.
}
Zdarzenia związane z wskaźnikiem są świetnym kandydatem do stopniowego ulepszania: wystarczy zmodyfikować metody inicjalizacji, aby wykonać powyższe sprawdzenie, dodać moduły obsługi zdarzeń związanych ze wskaźnikiem w bloku if
i przesunąć moduły obsługi zdarzeń związanych z myszą lub dotykiem do bloku else
.
Wypróbuj je i daj nam znać, co o nich myślisz.