Eventi JavaScript da zero

Quasi tutto ciò che fai in JavaScript dovrebbe iniziare quando succede qualcosa: l'utente fa clic su un pulsante, passa sopra un menu, preme un tasto, ti viene l'idea. È piuttosto semplice fare con librerie come jQuery, ma sai come collegare eventi in JavaScript non formattato? Oggi ti insegnerò proprio questo!


Benvenuto in JavaScript Events

Gestire eventi JavaScript non è scienza missilistica. Certo, ci sono differenze tra i browser (cosa ti aspettavi?), Ma una volta capito e costruito le tue personali funzioni di supporto anche per il campo di gioco, sarai contento che tu lo sappia. Anche se pensi ancora di usare una libreria per questo tipo di cose, è bello sapere cosa sta succedendo sotto la superficie. Eccoci qui.


Gestione eventi di livello 0

La gestione degli eventi più semplice in JavaScript è la gestione degli eventi di Livello 0. È piuttosto semplice: assegna la tua funzione alla proprietà dell'evento sull'elemento. Osservare:

 var element = document.getElementById ('myElement'); element.onclick = function () alert ('la tua funzione qui'); ;

Una volta ottenuto l'elemento, imposto il al clic proprietà uguale a una funzione. Ora, quando elemento viene cliccato, quella funzione verrà eseguita e vedremo una finestra di avviso.
Ma come sapevo usare al clic? È possibile ottenere un elenco di eventi disponibili su Wikipedia. Il bello del metodo Level 0 è che è supportato su tutti i browser oggi ampiamente utilizzati. Lo svantaggio è che puoi registrare ogni evento una volta sola con ciascun elemento. Quindi questo causerà solo un avviso:

 element.onclick = function () alert ('funzione 1'); ; element.onclick = function () alert ('I override function 1');

Solo la seconda funzione verrà eseguita quando si fa clic sull'elemento, perché abbiamo riassegnato la proprietà onclick. Per rimuovere un gestore di eventi, possiamo semplicemente impostarlo su null.

 element.onclick = null;

Sebbene fornisca solo funzionalità di base, il supporto coerente su tutti i browser rende l'evento di Livello 0 la gestione di un'opzione valida per progetti super-semplici.


Screencast completo



L'oggetto evento e questo

Ora che ti stai riscaldando negli eventi JavaScript, discutiamo di due aspetti importanti prima di passare a tecniche migliori: l'oggetto evento e il Questo parola chiave. Quando viene eseguito un evento, ci sono molte informazioni sull'evento che potresti voler sapere: quale tasto è stato premuto? quale elemento è stato cliccato? l'utente ha fatto clic con il pulsante sinistro, destro o centrale? Tutti questi dati e altro ancora sono memorizzati in un oggetto evento. Per tutti i browser eccetto Internet Explorer, è possibile accedere a questo oggetto passandolo come parametro alla funzione di gestione. In IE, puoi ottenerlo dalla variabile globale window.event. Non è difficile risolvere questa differenza.

 function myFunction (evt) evt = evt || window.event; / * ... * / element.onclick = myFunction;

myFunction accetta il parametro evento per tutti i browser validi e li riassegniamo a window.event Se EVT non esiste Vedremo alcune delle proprietà dell'oggetto evento un po 'più tardi.

Il Questo il keywork è importante nelle funzioni di gestione degli eventi; si riferisce all'elemento che ha ricevuto l'evento.

 element.onclick = function () this.style.backgroundColor = 'red'; // same as element.style.backgroundColor = 'red'; 

Sfortunatamente, in Internet Explorer, Questo non si riferisce all'elemento recitato; si riferisce all'oggetto finestra. Questo è inutile, ma vedremo un modo per porvi rimedio un po '.


Gestione degli eventi di livello 2

La gestione degli eventi di livello 2 è la specifica W3C per gli eventi DOM. È abbastanza semplice, in realtà.

 element.addEventListener ('mouseover', myFunction, false);

Il metodo è chiamato addEventListener. Il primo parametro è il tipo di evento che vogliamo ascoltare. Solitamente, è lo stesso nome degli eventi di Livello 0, senza il prefisso 'on'. Il secondo parametro è un nome di funzione o la funzione stessa. Il parametro finale determina se catturiamo o no; discuteremo di questo in un momento.
Uno dei grandi vantaggi dell'uso addEventListener è che ora possiamo assegnare più eventi per un singolo evento su un singolo elemento:

 element.addEventListener ('dblclick', logSuccessToConsole, false); element.addEventListener ('dblclick', function () console.log ('questa funzione non sovrascrive la prima.');, false);

Per rimuovere questi gestori, utilizzare la funzione removeEventListener. Quindi, per rimuovere la funzione che abbiamo aggiunto sopra, facciamo questo:

 element.removeEventListener ('dblclick', logSuccessToConsole, false);

Catturare e gorgogliare

Il parametro finale in addEventListner e removeEventListener è un booleano che definisce se spariamo all'evento nello stadio di cattura o gorgogliante. Ecco cosa significa:
Quando fai clic su un elemento, fai anche clic su ognuno dei suoi elementi antenati.

  
Salva lavoro

Se clicco sul campata # salva, Ho anche fatto clic div # barra degli strumenti, div # involucro, e corpo. Quindi, se qualcuno di questi elementi ha ascoltatori di eventi che ascoltano i clic, verranno chiamate le loro rispettive funzioni. Ma quale ordine dovrebbero essere chiamati? Questo è ciò che decide l'ultimo parametro. Nella specifica W3C, il nostro evento click sarebbe iniziato da corpo e spostati lungo la catena finché non raggiunge il campata # salva; questo è il palcoscenico che cattura. Quindi, va dal campata # salva di nuovo su corpo; questo è il palcoscenico gorgogliante. È facile da ricordare, perché le bolle fluttuano verso l'alto. Bolla di tutti gli eventi; quella tabella di Wikipedia ti dirà quali sono quelli che fanno e quali no.

Quindi se il parametro capture è impostato su vero, l'evento verrà attivato durante la discesa; se è impostato su falso, verrà attivato durante il passaggio.

Potresti aver notato che, finora, tutti i miei esempi hanno impostato l'acquisizione su false, quindi l'evento viene attivato nella fase di bubbling. Questo perché Internet Explorer non ha una fase di acquisizione. In IE, gli eventi hanno solo bolle.


Modello di eventi di Internet Explorer

IE ha il suo modo proprietario di lavorare con gli eventi. Utilizza attachEvent.

 element.attachEvent ('onclick', runThisFunction);

Dal momento che gli eventi IE si limitano a generare bolle, non è necessaria la terza variabile. I primi due sono gli stessi di addEventListener, con la grande eccezione che IE richiede il prefisso "on" per il tipo di evento. Naturalmente, con questo modello è possibile assegnare più eventi di un tipo a un singolo elemento. Per rimuovere eventi, utilizzare detachEvent.

 element.detachEvent ('onclick', runThisFunction);

Momentaneamente di nuovo a Bubbling

Che cosa succede se i tuoi elementi non vogliono che i loro genitori scoprano i loro eventi? Non è difficile da nascondere. In IE, usi il cancelBubble proprietà sull'oggetto evento che viene passato alla funzione chiamata. Per il resto, puoi usare il stopPropogation metodo, anche sull'oggetto evento.

 e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation (); 

Il stopPropogation il metodo fermerà anche gli eventi nelle loro tracce durante la fase di cattura.


Alcune proprietà dell'oggetto evento

Sarei disposto a scommettere che la maggior parte delle proprietà sull'oggetto evento andrà inutilizzata, ma ci sono alcune scelte che hai trovato inestimabili. Diamo un'occhiata a quei pochi.


bersaglio

Il bersaglio la proprietà è l'elemento più profondo su cui è stato fatto clic. Nell'immagine sopra, puoi vedere che ho cliccato Pulsante h1 #. In IE, questa proprietà viene chiamata srcElement; per ottenere questa proprietà, fai qualcosa di simile a questo:

 var target = e.target || e.srcElement;

currentTarget

Il currentTarget la proprietà è l'elemento che ha l'evento in questo momento. In quello screenshot, il currentTarget è div # involucro. Ciò significa che ho fatto clic Pulsante h1 #, ma l'oggetto evento è stato registrato nella console nella funzione chiamata da div # involucroL'ascoltatore di eventi.

Ma questo ti farà passare un ciclo: IE non ha una proprietà currentTarget o qualcosa del genere. Ricordando il fatto che IE non ha nemmeno lasciato Questo uguale all'elemento che innesca l'evento, questo significa che non abbiamo modo di ottenere l'elemento che ha innescato l'evento quando è in corso un bubbling (nel senso che è stato fatto clic su un discendente dell'elemento). Confuso? Forse un esempio aiuterà: se, in Internet Explorer, abbiamo questo HTML ...

 
Pulsante

... e questo gestore di eventi ...

 var par = document.getElementById ('parent'); parent.attachEvent ('onclick', doSomething);

... quindi, quando clicchiamo sul arco # bambino e l'evento bolle fino a div # genitore, non abbiamo modo dall'interno della funzione fare qualcosa per ottenere l'elemento (in questo caso, div # genitore) l'evento è stato attivato.

Altri

Ci sono altre proprietà sull'oggetto evento che troverai utili, a seconda dei casi. Su un evento di tastiera, (keyup, keydown, keypress), sarai il chiave e il charCode. Sarai in grado di dire se l'utente ha premuto il tasto alt, shift o ctrl (cmd) mentre si preme / si fa clic. Esplora gli oggetti evento di diversi eventi e guarda con cosa devi lavorare!


Fixing Events

Abbiamo riscontrato due problemi principali nel nostro studio degli eventi fino ad ora.

  • IE utilizza un modello diverso rispetto agli altri browser.
  • IE non ha modo di accedere all'oggetto padre dell'evento; manca il currentTarget proprietà, e il Questo l'oggetto fa riferimento all'oggetto della finestra.

Per risolvere questi problemi, creiamo due funzioni con supporto per browser, una per collegare eventi e una per rimuoverle.

Inizieremo con Aggiungi evento; ecco il primo round:

 var addEvent = function (element, type, fn) if (element.attachEvent) element.attachEvent ('on' + type, fn);  else element.addEventListener (type, fn, false); 

Sto assegnando una funzione anonima alla variabile Aggiungi evento per ragioni che vedrai tra un minuto. Tutto quello che dobbiamo fare è controllare se l'elemento ha il attachEvent metodo. Se lo fa, siamo in IE e useremo questo metodo. Se no, possiamo usare addEventListener.

Tuttavia, ciò non risolve il fatto che non abbiamo modo di accedere all'elemento padre dell'evento in IE. Per fare ciò, renderemo la funzione un attributo sull'elemento; in questo modo, è percepito come un metodo dell'elemento, e Questo sarà uguale all'elemento. Sì, lo so, brillante, non è vero? Beh, non posso prendermi alcun merito: questa idea viene da un post sul blog di John Resig.

 var addEvent = function (element, type, fn) if (element.attachEvent) element ['e' + type + fn] = fn; element [type + fn] = function () element ['e' + type + fn] (window.event); element.attachEvent ('on' + tipo, elemento [tipo + fn]);  else element.addEventListener (type, fn, false); 

La prima linea in più (element ['e' + type + fn] = fn;) rende la funzione un metodo dell'elemento, in modo che Questo ora sarà uguale all'elemento. La seconda riga è una funzione che esegue il metodo, passando nell'oggetto window.event. Questo ti risparmia il passaggio extra di verifica del parametro dell'oggetto evento all'interno della tua funzione. Infine, nota che abbiamo modificato il parametro della funzione in attachEvent metodo a elemento [tipo + fn].

Questo risolve i nostri due problemi. Ora possiamo usare il nostro Aggiungi evento funziona in tutti i browser con la maggior esperienza possibile. Ma c'è un po 'di ottimismo che vorremmo fare.

Notare che ogni volta il nostro Aggiungi evento la funzione è chiamata, controlla il attachEvent metodo. Non c'è motivo per cui dovremmo controllarlo più volte, indipendentemente da quanti eventi vogliamo registrare. Possiamo usare un trucco elegante che ci permetterà di riscrivere Aggiungi evento.

 var addEvent = function (el, type, fn) if (el.attachEvent) addEvent = function (el, type, fn) el ['e' + type + fn] = fn; el [tipo + fn] = funzione () el ['e' + tipo + fn] (window.event); ; el.attachEvent ('on' + tipo, el [tipo + fn]);  else addEvent = function (el, type, fn) el.addEventListener (type, fn, false);  addEvent (el, type, fn); 

Ora, se il Aggiungi evento il metodo è stato trovato, lo riscriveremo Aggiungi evento per includere solo le parti IE; in caso contrario, includeremo solo le buone parti del browser.
Nostro removeEvent la funzione sarà molto simile:

 var removeEvent = function (element, type, fn) if (element.detachEvent) removeEvent = function (element, type, fn) element.detachEvent ('on' + type, el [tipo + fn]); element [type + fn] = null;  else removeEvent = function (element, type, fn) element.removeEventListener (type, fn, false);  removeEvent (element, type, fn); 

Questo è tutto per le funzioni degli eventi cross-browser. C'è una cosa che non mi piace di loro, però: le funzioni non sono metodi degli elementi; invece, l'elemento è un parametro. So che è solo una questione di stile, ma mi piace

 btn.addEvent ('click', doThis);

meglio di

 addEvent (btn, 'click', doThis);

Potremmo fare questo avvolgendo le nostre funzioni in questo:

 var E = Element.prototype; E.addEvent = function (type, fn) addEvent (this, type, fn);  E.removeEvent = function (type, fn) removeEvent (this, type, fn); 

Questo funzionerà su tutti i browser moderni, così come su IE8; IE7 e IE6 si soffocano Elemento. Dipende dal tuo pubblico; Prendere o lasciare!


Delegazione degli eventi

Ora che sai tutto sugli eventi JavaScript, non precipitarti e riempire il tuo prossimo progetto con gli ascoltatori di eventi. Se hai molti elementi che rispondono allo stesso tipo di evento (ad esempio, fai clic), è più saggio approfittare del bubbling. È sufficiente aggiungere un listener di eventi a un elemento antenato, incluso il corpo, e utilizzare la proprietà target / srcElement sull'oggetto evento per determinare quale elemento più profondo è stato selezionato. Questo è chiamato Event Delegation. Ecco un esempio inutile:

Ecco alcuni HTML:

 
  • casa
  • portafoglio
  • di
  • contatto

Possiamo utilizzare la delega degli eventi per gestire i clic per ciascuno Li:

 function navigation (e) var el = e.target || e.srcElement; switch (el.id) case 'home': alert ('vai a casa'); rompere; caso 'portfolio': alert ('check out my products'); rompere; caso 'about': alert ('tutti quei dettagli disgustosi'); rompere; caso "contatto": avviso ("Sono lusingato che ti piacerebbe parlare"); rompere; default: alert ('come sei arrivato?');  var nav = document.getElementById ('nav'); addEvent (nav, 'click', navigazione);

Usiamo un'istruzione switch / case per esaminare l'id dell'elemento cliccato più profondo. Quindi, facciamo qualcosa di conseguenza.


Conclusione

Così ora puoi impugnare gli eventi JavaScript con il meglio di loro. Divertiti con esso e fai tutte le domande nei commenti!