I gemelli mouseenter e mouselascia Gli eventi elemento sono il modo standard per associare il codice JavaScript agli eventi al passaggio del mouse. Ma cosa succede se abbiamo bisogno di rilevare elementi hovered all’interno di un altro gestore di eventi? Io stesso ho dovuto rispondere a questa domanda quando ho implementato la gestione della messa a fuoco per dozzine di elementi SVG. Parte del trattamento della messa a fuoco inclusa l’annullamento di qualsiasi azione al passaggio del mouse corrente. Pensalo come il popolare gioco arcade whack-a-mole in cui i giocatori usano un martello per colpire talpe giocattolo che appaiono casualmente nei loro buchi. Dovrebbe apparire solo una talpa alla volta, quindi, se ogni talpa operava in modo autonomo, dovrebbe verificare se uno dei suoi compatrioti stava attualmente sporgendo dalla sua tana.
In questo tutorial, suoneremo una variazione di whack-a-mole in cui dovremo rilevare un elemento dell’immagine in bilico in modo da poter trasferire l’evidenziazione su un’altra immagine a fuoco.
Quando mouse e tastiera si scontrano
Di seguito è riportato l’HTML per la nostra demo. Contiene tre immagini che sono tabable grazie alla loro tabindex di “0”:
<h1>Hovered Element Demo</h1> <button type="button">Click me to start, then press the "tab" key</button> <p><img tabindex="0" src="https://i1.sndcdn.com/artworks-b5jyk6LpdxWVWWz5- jGpxXw-t200x200.jpg" /></p> <p><img tabindex="0" src="https://i1.sndcdn.com/ artworks-OCRwxXbSBQwex4mM- LY2qWg-t200x200.jpg" /></p> <p><img tabindex="0" src="https://i1.sndcdn.com/ artworks-2n1JKCcFA6Gg6UH7- GsP3HA-t200x200.jpg" /></p>
Al passaggio del mouse o messa a fuoco, vorremmo evidenziare l’immagine ingrandendola e aggiungendo un contorno tratteggiato blu, solo per una buona misura. Questo può essere fatto facilmente usando alcune regole CSS:
img { width: 150px; transition: transform .2s; } .highlight { left: 50px; transform: scale(1.5) translate(25px); outline: 2px blue dashed; }
Senza una gestione speciale, non ci sarebbe nulla che ci impedisca di passare a un’immagine con il tab mentre si passa con il mouse su puntatore del mouse sopra un altro. Modo per confondere l’utente!
Rilevamento di immagini focalizzate con JavaScript
Determinare l’elemento attualmente focalizzato è semplice, grazie al documento elemento attivo proprietà. Quello che è un po’ più complicato è capire se l’elemento attualmente focalizzato è o meno una delle nostre immagini. Ci sono un paio di modi per farlo (probabilmente di più):
- Potremmo verificare se l’elemento attualmente focalizzato è un figlio del contenitore genitore usando il metodo jQuery.contains(). Lo svantaggio di questo approccio è che jQuery.contains() controlla TUTTI i bambini, non solo le immagini che ci interessano.
- Dal momento che abbiamo bisogno di memorizzare tutte le immagini attivabili per allegare loro gestori di eventi, perché non vedere se riusciamo a trovare il elemento attivo all’interno della collezione?
Per me, è stato un gioco da ragazzi; il secondo approccio è stata la scelta chiara. Mentre le raccolte DOM jQuery non hanno un metodo di “ricerca” di per sé, offrono index(). Cerca un dato elemento tra gli elementi corrispondenti e restituisce il suo indice numerico, proprio come indexOf() dell’array JS nativo. Se non viene passato alcun argomento al metodo .index(), restituisce la posizione del primo elemento all’interno dell’oggetto jQuery rispetto ai suoi elementi di pari livello. Quando viene passata una stringa di selezione, il valore restituito è la posizione del primo elemento all’interno dell’oggetto jQuery rispetto agli elementi che corrispondono al selettore. Se l’elemento non viene trovato, .index() restituirà -1:
var images = $('img'); images.hover(function(elt) { if (images.index(document.activeElement) === -1) { $(this).toggleClass(' highlight'); } })
Passare una singola funzione a $(selector).hover(
, lo renderà il gestore sia per gli eventi mouseenter che mouseleave. Questo ci consente di utilizzare il metodo generico toggleClass() di jQuery all’interno del gestore. Aggiungerà la classe quando non è presente e la rimuoverà quando lo è.
Rilevamento di immagini al passaggio del mouse
Ora entriamo nel vivo dell’articolo. Ti aspetti una pagina intera di codice? Non preoccuparti, c’è un modo semplice per farlo. Il trucco non così segreto è la pseudo-classe :hover, la stessa che usi per lo stile CSS. È un selettore speciale, quindi possiamo usarlo per fare riferimento all’elemento attualmente sospeso o, più specificamente, all’intera catena di bubbling dall’elemento sorgente fino al tag HTML. Ecco il codice che restituisce l’immagine attualmente sospesa (o non definito se nessuno viene spostato sopra):
function getHoveredImage() { var hoveredElements = $(':hover'), // the last element is the event source hoveredElement = hoveredElements.last(); if (hoveredElement.prop("tagName") === 'IMG') { return hoveredElement; } }
Gli oggetti jQuery non sono mai non definito, quindi è perfettamente sicuro controllare le proprietà e ad esempio se un elemento è attualmente al passaggio del mouse o meno. Ecco un paio di esempi di raccolte DOM restituite da $(‘:hover’) – uno in cui viene passato il pulsante in alto e un altro in cui una delle nostre immagini è la sorgente del passaggio del mouse:
Nel gestore della messa a fuoco, ora possiamo disattivare l’evidenziazione sull’immagine al passaggio del mouse, se necessario:
.focus(function() { var hoveredImage = getHoveredImage(); //turn off hover highlighting if (hoveredImage) { hoveredImage.removeClass('highlight'); } $(this).toggleClass(' highlight', true); })
Non c’è bisogno di un controllo simile nel gestore della sfocatura perché gli accessi del mouse vengono bloccati una volta che l’immagine è a fuoco. C’è un po’ di codice in più qui per riportare lo stato attivo sull’immagine in alto in modo che possiamo TAB sulle immagini in un ciclo:
.blur(function(evt) { $(this).removeClass('highlight', false); //This code resets the focus on the 1st image //so that you can keep on tabbing through the images. if (evt.target === images.last().get(0)) { setTimeout(function() { images.first().focus(); }, 1); } });
La dimostrazione
Sopra codepen.io, troverai la demo con tutto il codice presentato in questo articolo.
Conclusione
Nell’articolo di oggi abbiamo imparato un sacco di cose utili, come come rilevare gli elementi attualmente in bilico e/o focalizzati, trovare un elemento all’interno di una raccolta DOM e come raggruppare mouseenter e mouselascia gestori di eventi in una singola funzione. Tieni presente che tutto ciò che abbiamo fatto qui oggi può essere ottenuto senza l’aiuto di jQuery, ma perché preoccuparsi? È onnipresente e spacca!