Kiedyś zwracanie uwagi na rzeczy w internecie było proste. Chodziło o myszkę, poruszaliśmy nią, naciskaliśmy przyciski i tak dalej. Wszystko, co nie było myszką, było emulowane jako jedno, a deweloperzy wiedzieli, na co dokładnie liczyć.
Prostota nie musi być jednak łatwa. Z czasem coraz ważniejsze było to, że nie wszystko było (lub udawało) myszką. Mając pióra czułe na nacisk i z odchyleniem, aby wykazać się twórczą swobodą, wystarczyło już tylko urządzenie i dłoń, a do tego można było używać więcej niż 1 palca.
Od jakiegoś czasu używamy zdarzeń dotyku, aby nam w tym pomagać, ale są to zupełnie odrębne interfejsy API przeznaczone specjalnie do obsługi dotyku. Jeśli chcesz obsługiwać zarówno mysz, jak i dotyk, musisz zakodować 2 osobne modele zdarzeń. W Chrome 55 obowiązuje nowszy standard, który ujednolica oba modele: zdarzenia wskaźnika.
Model pojedynczego zdarzenia
Zdarzenia wskaźnika ujednolicają model wprowadzania wskaźnika dla przeglądarki, łącząc dotyk, pióra i myszy w jeden zestaw zdarzeń. 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óre powinny wyglądać znajomo, jeśli znasz się na zdarzeniach myszy:
pointerover
|
Wskaźnik wszedł do ramki ograniczającej elementu.
Dzieje się tak natychmiast w przypadku urządzeń, które obsługują najechanie kursorem, lub przed zdarzeniem pointerdown w przypadku urządzeń, które nie obsługują tej funkcji.
|
pointerenter
|
Podobna do pointerover , ale nie wyświetla się jako dymki i obsługuje elementy podrzędne w inny sposób.
Szczegółowe informacje o specyfikacji.
|
pointerdown
|
Wskaźnik wszedł w stan aktywnego przycisku i został naciśnięty przycisk lub nawiązywany jest kontakt w zależności od semantyki urządzenia wejściowego. |
pointermove
|
Wskaźnik zmienił położenie. |
pointerup
|
Wskaźnik pozostawił aktywny przycisk. |
pointercancel
|
Stało się coś, co oznacza, że wskaźnik prawdopodobnie nie będzie generować więcej zdarzeń. Oznacza to, że należy anulować wszystkie trwające działania i wrócić do neutralnego stanu danych wejściowych. |
pointerout
|
Wskaźnik opuścił ramkę ograniczającą elementu lub ekranu. Podobnie po pointerup , jeśli urządzenie nie obsługuje najechania kursorem.
|
pointerleave
|
Podobna do pointerout , ale nie wyświetla się jako dymki i obsługuje elementy podrzędne w inny sposób.
Szczegółowe informacje o specyfikacji.
|
gotpointercapture
|
Element otrzymał zapis wskaźnika. |
lostpointercapture
|
Przechwytywany wskaźnik został zwolniony. |
Różne typy danych wejściowych
Ogólnie rzecz biorąc, zdarzenia wskaźnika pozwalają pisać kod w sposób niezależny od danych wejściowych, bez konieczności rejestrowania osobnych modułów obsługi zdarzeń dla różnych urządzeń wejściowych.
Oczywiście nadal musisz pamiętać o różnicach między typami danych wejściowych, np. o tym, czy pojawia się pojęcie najechania kursorem. Jeśli chcesz rozróżniać różne typy urządzeń wejściowych (na przykład aby udostępniać oddzielny kod/funkcje dla różnych danych wejściowych), możesz to jednak zrobić w tych samych modułach obsługi zdarzeń za pomocą właściwości pointerType
interfejsu PointerEvent
. Jeśli np. kodujesz panel nawigacji bocznej, w zdarzeniu pointermove
możesz mieć taką logiczną logikę:
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ą dotykową niektóre gesty służą do przewijania, powiększania i odświeżania strony.
W przypadku zdarzeń dotknięcia nadal będziesz otrzymywać zdarzenia w trakcie wykonywania tych działań domyślnych, np. gdy użytkownik przewija stronę, wywoływany będzie touchmove
.
W przypadku zdarzeń wskaźnika po każdym wywołaniu działania domyślnego, np. przewijania lub powiększania, stosowane jest zdarzenie pointercancel
informujące, że przeglądarka przejęła kontrolę nad wskaźnikiem. 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ą skuteczność w porównaniu ze zdarzeniami dotknięciami, w przypadku których osiągnięcie takiego samego poziomu reagowania wymaga użycia pasywnych detektorów zdarzeń.
Możesz zatrzymać przeglądarkę, używając właściwości CSS touch-action
. Ustawienie dla elementu wartości none
spowoduje wyłączenie wszystkich działań zdefiniowanych w przeglądarce, które rozpoczynają się w związku z tym elementem. Istnieje jednak jeszcze szereg innych wartości umożliwiających bardziej szczegółową kontrolę, np. pan-x
, które umożliwiają przeglądarce reagowanie na ruchy na osi X, ale nie na osi Y. Chrome 55 obsługuje te wartości:
auto
|
Domyślnie; przeglądarka może wykonywać dowolne domyślne działania. |
none
|
Przeglądarka nie może wykonywać żadnych domyślnych działań. |
pan-x
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w poziomie. |
pan-y
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w pionie. |
pan-left
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w poziomie i przesuwać stronę w lewo. |
pan-right
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w poziomie i przesuwać stronę w prawo. |
pan-up
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w pionie i tylko przesuwać stronę w górę. |
pan-down
|
Przeglądarka może wykonywać tylko domyślne działanie przewijania w pionie i tylko przesuwać stronę w dół. |
manipulation
|
Przeglądarka może wykonywać tylko czynności przewijania i powiększania. |
Przechwytywanie wskaźnika
Czy zdarzyło Ci się spędzić frustrującą godzinę na debugowaniu uszkodzonego zdarzenia mouseup
, dopóki nie zorientujesz się, że to dlatego, że użytkownik puszcza przycisk poza Twoim celem kliknięcia? Nie? W takim razie może to tylko ja.
Do tej pory nie było jednak żadnego dobrego sposobu na radzenie sobie z tym problemem. Oczywiście, możesz skonfigurować moduł obsługi mouseup
w dokumencie i zapisać stan aplikacji, aby śledzić informacje. Nie jest to jednak najprostsze rozwiązanie, zwłaszcza jeśli tworzysz komponent witryny i chcesz, by wszystko było w porządku i odizolowane.
Zdarzenia typu wskaźnik są znacznie lepsze: możesz zarejestrować wskaźnik, aby mieć pewność, że zdarzenie pointerup
(lub któregokolwiek z jego nieuchwytnych znajomych) zostanie odebrane.
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ługiwane przeglądarki
W momencie tworzenia tego tekstu zdarzenia wskaźników są obsługiwane w przeglądarkach Internet Explorer 11, Microsoft Edge, Chrome i Opera, a częściowo obsługiwane w przeglądarce Firefox. Aktualną listę znajdziesz na stronie caniuse.com.
Do wypełniania luk możesz użyć kodu polyfill zdarzeń wskaźnika. Aby sprawdzić obsługę przeglądarek w czasie działania aplikacji, możesz też sprawdzić to w prosty sposób:
if (window.PointerEvent) {
// Yay, we can use pointer events!
} else {
// Back to mouse and touch events, I guess.
}
Zdarzenia wskaźnika doskonale nadają się do stopniowego udoskonalania: wystarczy zmodyfikować metody inicjowania, aby wykonać powyższy test, dodać moduły obsługi zdarzeń wskaźnika w bloku if
, a potem przenieść moduły obsługi zdarzeń myszy/dotyku do bloku else
.
Wypróbuj go i daj nam znać, co o nim myślisz.