Indicare la strada da seguire

Sérgio Gomes

Indicare le cose sul web era semplice. Avevi un mouse, l'hai spostato in giro, a volte premi i pulsanti, ed è tutto. Tutto ciò che non era del mouse è stato emulato come tale e gli sviluppatori sapevano esattamente su cosa contare.

Tuttavia, semplice non significa necessariamente che sia buono. Nel corso del tempo, è diventata sempre più importante che non tutto fosse (o abbia finto di essere) un topo: potevi fare penne sensibili alla pressione e inclinate, per una straordinaria libertà creativa; potresti usare le dita, quindi tutto ciò di cui servivano il dispositivo e la mano; e hey, perché non usare più di un dito mentre ci sei?

Si sono verificati eventi touch per un po' di tempo per aiutarci, ma sono API completamente separate appositamente per il tocco, che ti costringe a programmare due modelli di eventi separati se vuoi supportare sia il mouse che il tocco. Chrome 55 viene fornito con uno standard più recente che unifica entrambi i modelli: eventi puntatore.

Un modello a evento singolo

Gli eventi del puntatore unificano le modello di input del puntatore per il browser, che unisce tocco, penne e mouse in un unico insieme di eventi. Ad esempio:

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

Ecco un elenco di tutti gli eventi disponibili, che dovrebbe esserti familiare se hai familiarità con gli eventi del mouse:

pointerover Il puntatore è entrato nel riquadro di delimitazione dell'elemento. Questo avviene immediatamente per i dispositivi che supportano il passaggio del mouse o prima di un pointerdown evento per i dispositivi che non lo fanno.
pointerenter Simile a pointerover, ma non mostra bolle e punti di manipolazione discendenti in modo diverso. Dettagli sulle specifiche.
pointerdown Il puntatore è nello stato di pulsante attivo e un pulsante è o un contatto, in base alla semantica del dispositivo di input.
pointermove Il puntatore ha cambiato posizione.
pointerup Il puntatore ha lasciato lo stato del pulsante attivo.
pointercancel È successo qualcosa che significa che è improbabile che il puntatore emetta più eventi. Ciò significa che devi annullare le azioni in corso e per tornare allo stato di input neutro.
pointerout Il puntatore ha lasciato il riquadro di delimitazione dell'elemento o della schermata. Anche dopo un pointerup, se il dispositivo non supporta il passaggio del mouse.
pointerleave Simile a pointerout, ma non mostra bolle e punti di manipolazione discendenti in modo diverso. Dettagli sulle specifiche.
gotpointercapture L'elemento ha ricevuto l'acquisizione del puntatore.
lostpointercapture Il puntatore in fase di acquisizione è stato rilasciate.

Diversi tipi di input

In genere, gli eventi puntatore consentono di scrivere codice in modo indipendente dall'input, senza dover registrare gestori di eventi separati per i diversi dispositivi di input. Ovviamente, dovrai comunque fare attenzione alle differenze tra i tipi di input, ad esempio se si applica il concetto di passaggio del mouse. Se vuoi distinguere i diversi tipi di dispositivi di input, magari per fornire separatamente codice/funzionalità per i diversi input, ma puoi farlo all'interno degli stessi gestori di eventi utilizzando la proprietà pointerType dell'elemento PointerEvent a riga di comando. Ad esempio, se stavi programmando un riquadro di navigazione a scomparsa laterale, potresti avere la seguente logica sul tuo evento 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;
}

Azioni predefinite

Nei browser abilitati al tocco, alcuni gesti vengono utilizzati per far scorrere, aumentare lo zoom o aggiornare la pagina. Nel caso di eventi touch, riceverai comunque gli eventi mentre questi predefiniti sono in corso. Ad esempio, touchmove verrà comunque attivato mentre l'utente scorre la pagina.

Con gli eventi del puntatore, ogni volta che viene attivata un'azione predefinita come scorrimento o zoom, riceverai un evento pointercancel per farti sapere che il browser ha eseguito controllo del puntatore. Ad esempio:

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

Velocità integrata: per impostazione predefinita, questo modello consente prestazioni migliori. rispetto agli eventi touch, per i quali bisognerebbe usare Listener di eventi passivi per raggiungere lo stesso livello di reattività.

Puoi impedire al browser di assumere il controllo con touch-action proprietà CSS. Se viene impostato su none in un elemento, vengono disattivati tutti azioni definite dal browser avviate su quell'elemento. Ma ci sono una serie di altri valori per un controllo più granulare, ad esempio pan-x, per consentire il browser in modo che reagisca al movimento sull'asse x ma non sull'asse y. Chrome 55 supporta i seguenti valori:

auto Valore predefinito; il browser può eseguire qualsiasi azione predefinita.
none Il browser non è autorizzato a eseguire azioni predefinite.
pan-x Il browser può eseguire solo l'azione predefinita di scorrimento orizzontale.
pan-y Il browser può eseguire solo l'azione predefinita di scorrimento verticale.
pan-left Il browser può eseguire solo l'azione predefinita di scorrimento orizzontale, e solo per spostare la pagina verso sinistra.
pan-right Il browser può eseguire solo l'azione predefinita di scorrimento orizzontale, e solo per spostare la pagina verso destra.
pan-up Il browser può eseguire solo l'azione predefinita di scorrimento verticale. e solo per spostare la pagina verso l'alto.
pan-down Il browser può eseguire solo l'azione predefinita di scorrimento verticale. e solo per eseguire la panoramica della pagina verso il basso.
manipulation Il browser può eseguire soltanto azioni di scorrimento e zoom.

Acquisizione del puntatore

Ti è mai capitato di trascorrere un'ora frustrante a eseguire il debug di un mouseup guasto finché non ti renderai conto che è perché l'utente ha lasciato il pulsante. al di fuori del target di clic? No? Ok, forse sono solo io, allora.

Eppure, non c'era un modo davvero valido per affrontare questo problema. Certo, puoi impostare il gestore mouseup sul documento e salvare lo stato dell'applicazione per tenere traccia delle cose. Non è la soluzione più pulita, Tuttavia, in particolare se devi creare un componente web e cercare di mantenere tutto in regola e isolata.

Gli eventi puntatore offrono una soluzione molto migliore: è possibile acquisire il puntatore, per assicurarti di ottenere quell'evento pointerup (o qualsiasi altro dei suoi eventi amici).

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!'));

Supporto browser

Al momento della scrittura, gli eventi puntatore sono supportati in Internet Explorer 11. Microsoft Edge, Chrome e Opera e parzialmente supportato in Firefox. Puoi consulta un elenco aggiornato all'indirizzo caniuse.com.

Puoi utilizzare il polyfill degli eventi puntatore per colmare le lacune. In alternativa, il controllo del supporto del browser in fase di runtime semplice:

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

Gli eventi Puntatore sono ideali per il miglioramento progressivo: modifica i metodi di inizializzazione per effettuare il controllo riportato sopra, aggiungi evento puntatore nel blocco if e sposta i gestori di eventi mouse/touch nel Blocco else.

Quindi, provali e facci sapere la tua opinione.