20 aprile 2021

Eventi del mouse

In questo capitolo andremo un po’ più a fondo sugli eventi del mouse e le loro proprietà.

Nota bene: questi eventi potrebbero derivare non solo da “dispositivi mouse”, ma anche da dispositivi di altro tipo, come telefoni e tablets, nei quali sono emulati per compatibilità.

Tipi di eventi del mouse

Abbiamo visto precedentemente alcuni di questi eventi:

mousedown/mouseup
Il pulsante del mouse viene premuto/rilasciato su un elemento.
mouseover/mouseout
Il puntatore del mouse passa sopra/abbandona un elemento.
mousemove
Ogni movimento del mouse su un elemento genera questo evento.
click
Scaturito dopo l’evento mousedown e quindi mouseup sullo stesso elemento se viene usato il pulsante sinistro del mouse.
dblclick
Generato quando avvengono due click sullo stesso elemento in un piccolo intervallo di tempo. Oggigiorno usato raramente.
contextmenu
Scaturito quando viene premuto il pulsante destro del mouse. Ci sono altri modi per aprire un menù contestuale, per esempio usando un particolare tasto della tastiera, quindi viene generato anche in quest’ultimo caso e non è propriamente un evento del mouse.

…Ci sono tanti altri eventi, che affronteremo successivamente.

Ordine degli eventi

Come possiamo notare dalla lista appena descritta, un’azione dell’utente può generare eventi multipli.

Per esempio, un click sul pulsante sinistro del mouse genera mousedown, quando il pulsante viene premuto, quindi mouseup e click quando viene rilasciato.

Quando un’azione singola inizia eventi multipli, il loro ordine è fisso. Ossia, i gestori vengono chiamati nell’ordine mousedownmouseupclick.

Premi il seguente pulsante e vedrai gli eventi. prova anche il doppio click.

Nel banco di prova in basso, vengono elencati tutti gli eventi del mouse, e se passa più di un secondo tra uno e l’altro vengono separati da una riga orizzontale.

Possiamo inoltre notare la proprietà button che permette di rilevare il pulsante del mouse, viene spiegato successivamente.

Pulsante del mouse

Gli eventi relativi al click contengono sempre la proprietà button, che permette di conoscere esattamente quale pulsante del mouse viene premuto.

Solitamente non lo usiamo per gli eventi click e contextmenu, perché il primo avviene solo per il click sul pulsante sinistro, ed il secondo – solo per quelli sul tasto destro.

D’altra parte, i gestori mousedown e mouseup potrebbero necessitare di event.button, in quanto questi eventi vengono generati su qualunque pulsante, quindi button permette di discriminare tra “mousedown destro” e “mousedown sinistro”.

I valori possibili di event.button sono:

Button state event.button
Pulsante sinistro (principale) 0
Pulsante medio (ausiliario) 1
Pulsante destro (secondario) 2
Pulsante X1 (indietro) 3
Pulsante X2 (avanti) 4

La maggioranza dei mouse hanno solo il tasto destro e sinistro, quindi i valori possibili sono 0 o 2. Anche i dispositivi touch generano event simili al tocco.

Inoltre esiste la proprietà event.buttons che include tutti i pulsanti attualmente premuti, rappresentati come numero intero, una cifra per pulsante. In pratica questa proprietà viene usata raramente, ma si possono trovare i dettagli su MDN in caso di necessità.

L’obsoleta event.which

Codice più antiquato potrebbe fare uso della proprietà event.which che è un vecchio e non standard modo di ottenere informazioni sul pulsante, con questi possibili valori:

  • event.which == 1 – pulsante sinistro,
  • event.which == 2 – pulsante centrale,
  • event.which == 3 – pulsante destro.

Attualmente, event.which è deprecato e non dovremmo usarlo.

Modificatori: shift, alt, ctrl e meta

Tutti gli eventi del mouse includono informazioni circa i tasti modificatori premuti.

Proprietà dell’evento:

  • shiftKey: Shift
  • altKey: Alt (oppure Opt per Mac)
  • ctrlKey: Ctrl
  • metaKey: Cmd per Mac

Vengono valorizzati a true quando il tasto corrispondente viene premuto.

Per esempio, il seguente pulsante funziona solamente con Alt+Shift+click:

<button id="button">Alt+Shift+Click qui!</button>

<script>
  button.onclick = function(event) {
    if (event.altKey && event.shiftKey) {
      alert('Urrà!');
    }
  };
</script>
Attenzione: su Mac solitamente si usa Cmd invece di Ctrl

Su Windows e Linux esistono i tasti modificatori Alt, Shift e Ctrl. Su Mac ne esiste uno in più: Cmd, corrispondente alla proprietà metaKey.

Nella maggior parte delle applicazioni, quando Windows/Linux usano Ctrl, su Mac si usa Cmd.

Ossia: quando un utente Windows preme Ctrl+Enter o Ctrl+A, un utente Mac premerebbe Cmd+Enter o Cmd+A, e così via.

Ne consegue che se vogliamo dare supporto a combinazioni di tasti come Ctrl+click, allora per Mac ha senso usare Cmd+click, che è molto più comodo per utenti Mac.

Anche se volessimo forzare gli utenti Mac a usare Ctrl+click – si va incontro a una certa tipologia di ostacolo. Il problema è che: un click col tasto destro con un Ctrl su Mac viene interpretato come un click sul tasto destro, e genera l’evento contextmenu, non un click come su Windows/Linux.

Quindi se vogliamo che gli utenti di tutti i sistemi operativi lavorino si sentano a proprio agio, allora insieme a ctrlKey dovremmo controllare metaKey.

Per il codice JS ciò significa che dovremmo controllare if (event.ctrlKey || event.metaKey).

Esistono anche i dispositivi mobile

Le combinazioni di tasti vanno bene in aggiunta al flusso di lavoro. Quindi se il visitatore usa una tastiera – andranno bene.

Ma in mancanza di questa – allora dovrebbe esserci una maniera per poter “vivere” senza tasti modificatori.

Coordinate: clientX/Y, pageX/Y

Tutti gli eventi del mouse forniscono le coordinate in due modi:

  1. Relative alla Window: clientX e clientY.
  2. Relative al Document: pageX e pageY.

Abbiamo già affrontato la differenza tra le due nel capitolo Coordinate.

In soldoni, le coordinate relative al documento pageX/Y vengono misurate a partire dall’angolo in alto a sinistra del documento, e non cambiano se la pagina viene scrollata, mentre invece clientX/Y vengono misurate a partire dall’angolo in alto a sinistra della finestra. Quando la pagina viene scrollata, i loro valori cambiano.

Per esempio, se avessimo una finestra di dimensioni 500x500, ed il puntatore del mouse fosse nell’angolo in alto a destra, allora clientX e clientY sarebbero valorizzate a 0, senza alcuna considerazione del fatto che la pagina sia scrollata o meno.

E se il puntatore fosse al centro, allora clientX e clientY sarebbero valorizzati a 250, senza tenere conto del punto in cui si trovi rispetto al documento. In qualche modo sono simili a position:fixed da questo punto di vista.

Muovere il mouse sopra il campo di testo per vedere clientX/clientY (l’esempio è dentro un iframe, quindi le coordinate sono relative a questo iframe):

<input onmousemove="this.value=event.clientX+':'+event.clientY" value="Muovi il mouse sopra me">

Prevenire la selezione su mousedown

Il doppio click del mouse ha un effetto collaterale che potrebbe dare fastidio in alcune interfacce: seleziona il testo.

Per esempio, il doppio click sul seguente testo lo seleziona in aggiunta al nostro gestore:

<span ondblclick="alert('dblclick')">Doppio click su di me</span>

Se si preme sul pulsante sinistro del mouse e, senza rilasciarlo, si muove il mouse, si ottiene una selezione, spesso non voluta.

Ci sono vari modi per prevenire la selezione, consultabili nel capitolo Selection e Range.

In questo caso particolare la maniera più ragionevole è di prevenire l’azione del browser su mousedown. La cosa previene entrambe queste selezioni:

Prima...
<b ondblclick="alert('Click!')" onmousedown="return false">
  Double-click me
</b>
...Dopo

Adesso l’elemento in grassetto non viene selezionato al doppio click, e premendo il pulsante sinistro su di esso non comincerà la selezione.

Nota bene: il testo all’interno è ancora selezionabile. Comunque, la selezione dovrebbe cominciare non sul testo stesso, ma prima o dopo di esso. Solitamente la cosa è accettabile per gli utenti.

Prevenire la copia

Se volessimo disabilitare la selezione per proteggere il contenuto della nostra pagina dal copia-incolla, potremmo usare un altro evento: oncopy.

<div oncopy="alert('Copying forbidden!');return false">
  Caro utente,
  La copia è vietata.
  Sebbene, nel caso in cui tu conosca JS or HTML, allora potrai prendere tutto dal sorgente della pagina.
</div>

Se provassimo a copiare un pezzo del testo all’interno del <div>, la copia non andrà a buon fine, perché l’azione predefinita oncopy sarà stata prevenuta.

Sicuramente l’utente ha accesso al sorgente HTML della pagina, e potrà prendere il contenuto da lì, ma non tutti conoscono come farlo.

Riepilogo

Gli eventi del mouse contengono le seguenti proprietà:

  • Pulsante: button.

  • Tasti modificatori (true se premuto): altKey, ctrlKey, shiftKey e metaKey (Mac).

    • Se vogliamo gestire Ctrl, allora non dobbiamo dimenticarci degli utenti Mac, che solitamente usano Cmd, quindi sarebbe meglio controllare if (e.metaKey || e.ctrlKey).
  • Coordinate relative alla Window: clientX/clientY.

  • Coordinate relative al Document: pageX/pageY.

L’azione predefinita del browser di mousedown è la selezione del testo, se non è cosa gradita per l’interfaccia, allora dovrebbe essere prevenuta.

Nel prossimo capitolo vedremo più in dettaglio gli eventi che seguono i movimenti del puntatore e come tenere traccia degli elementi che cambiano sotto di esso.

Esercizi

importanza: 5

Create una lista nella quale gli elementi siano selezionabili, come nei file manager.

  • Un click su una lista seleziona solo quell’elemento (aggiunge la classe .selected), e deseleziona tutti gli altri.
  • Se un click viene fatto insieme a Ctrl (Cmd per Mac), allora la seleziona viene alternata sull’elemento, ma gli altri elementi non vengono modificati.

La demo:

P.S.: Per questo compito possiamo assumere che questi elementi siano composti solamente da testo. Nessun tag annidato.

P.P.S.: Prevenire la selezione nativa del browser sul testo al click.

Apri una sandbox per l'esercizio.

Mappa del tutorial

Commenti

leggi questo prima di lasciare un commento…
  • Per qualsiasi suggerimento - per favore, apri una issue su GitHub o una pull request, piuttosto di lasciare un commento.
  • Se non riesci a comprendere quanto scitto nell'articolo – ti preghiamo di fornire una spiegazione chiara.
  • Per inserire delle righe di codice utilizza il tag <code>, per molte righe – includile nel tag <pre>, per più di 10 righe – utilizza una sandbox (plnkr, jsbin, codepen…)