Nesten alt du gjør i JavaScript, skal begynne når noe skjer: brukeren klikker på en knapp, svinger over en meny, trykker på en tast, du får ideen. Det er ganske enkelt å gjøre med biblioteker som jQuery, men vet du hvordan du kobler opp hendelser i rå JavaScript? I dag skal jeg bare lære deg det!
Håndtering av JavaScript-hendelser er ikke rakettvitenskap. Selvfølgelig er det nettleserforskjeller (hva forventet du?), Men når du får tak i det og bygger dine egne hjelpefunksjoner til enda lekeplassen, vil du være glad du vet det. Selv om du fortsatt planlegger å bruke et bibliotek for denne typen ting, er det godt å vite hva som skjer under overflaten. Her går vi.
Den mest grunnleggende hendelseshåndteringen i JavaScript er Nivå 0 hendelseshåndtering. Det er ganske enkelt: Tilordne bare funksjonen til hendelsesegenskapen på elementet. Observere:
var element = document.getElementById ('myElement'); element.onclick = function () alert ('din funksjon her'); ;
Når jeg har elementet, setter jeg ved trykk
eiendom som er lik en funksjon. Nå, når element
er klikket, vil denne funksjonen løpe, og vi får se en advarselsboks.
Men hvordan visste jeg å bruke ved trykk
? Du kan få en liste over tilgjengelige hendelser på Wikipedia. Skjønnheten om nivå 0-metoden er at den støttes på alle nettlesere som brukes mye i dag. Ulempen er at du kun kan registrere hver hendelse en gang med hvert element. Så dette vil bare føre til en advarsel:
element.onclick = funksjon () alarm ('funksjon 1'); ; element.onclick = function () alert ('Jeg overstyrer funksjon 1');
Bare den andre funksjonen vil kjøre når elementet klikkes, fordi vi har tilordnet den onclick-egenskapen. For å fjerne en hendelseshåndterer, kan vi bare sette den til null.
element.onclick = null;
Selv om det bare gir grunnleggende funksjonalitet, gjør konsistent støtte over alle nettlesere Nivå 0-hendelseshåndtering et gyldig alternativ for super enkle prosjekter.
Nå som du varmer opp i JavaScript-hendelser, la oss diskutere to viktige fasetter før du går videre til bedre teknikker: hendelsesobjektet og dette
søkeord. Når en hendelse blir utført, er det mye informasjon om hendelsen du kanskje vil vite: hvilken nøkkel ble presset? hvilket element ble klikket? klarte brukeren med venstre, høyre eller mellomknappen? Alle disse dataene og mer lagres i et hendelsesobjekt. For alle nettlesere unntatt Internet Explorer, kan du komme til dette objektet ved å sende det som en parameter til håndteringsfunksjonen. I IE kan du få det fra den globale variabelen window.event
. Det er ikke vanskelig å løse denne forskjellen.
funksjon myFunction (evt) evt = evt || window.event; / * ... * / element.onclick = myFunction;
myFunction
tar hendelsesparameteren for alle gode nettlesere, og vi overfører den til window.event
hvis evt
eksisterer ikke. Vi ser på noen av egenskapene til hendelsesobjektet litt senere.
De dette
nøkkelarbeid er viktig innen hendelseshåndteringsfunksjoner; det refererer til elementet som mottok arrangementet.
element.onclick = funksjon () this.style.backgroundColor = 'rød'; // samme som element.style.backgroundColor = 'rød';
Dessverre, i Internet Explorer, dette
refererer ikke til det oppførte elementet; det refererer til vinduet objektet. Det er ubrukelig, men vi ser på en måte å avhjelpe det på litt.
Nivå 2 hendelseshåndtering er W3C-spesifikasjonen for DOM-hendelser. Det er ganske enkelt, faktisk.
element.addEventListener ('mouseover', myFunction, false);
Metoden kalles addEventListener
. Den første parameteren er den type arrangement vi vil lytte til. Vanligvis er det samme navn som nivå 0-hendelsene, uten 'på' prefiks. Den andre parameteren er enten et funksjonsnavn eller selve funksjonen. Den endelige parameteren bestemmer om vi tar opp eller ikke; Vi diskuterer dette på et øyeblikk.
En av de store fordelene ved å bruke addEventListener
er at vi nå kan tilordne flere hendelser for en enkelt hendelse på et enkelt element:
element.addEventListener ('dblclick', logSuccessToConsole, false); element.addEventListener ('dblclick', funksjon () console.log ('denne funksjonen overstyrer ikke den første.');, false);
For å fjerne disse håndteringene, bruk funksjonen removeEventListener
. Så, for å fjerne funksjonen vi la til ovenfor, gjør vi dette:
element.removeEventListener ('dblclick', logSuccessToConsole, false);
Den endelige parameteren i addEventListner
og removeEventListener
er en boolsk som definerer om vi brann hendelsen i fangst eller boblende scenen. Her er hva det betyr:
Når du klikker på et element, klikker du også på hver av sine forfedreelementer.
Lagre arbeid
Hvis jeg klikker på span # spare
, Jeg har også klikket div # verktøylinje
, div # wrapper
, og kropp
. Så hvis noen av disse elementene har hendelseslyttere som lytter etter klikk, blir deres respektive funksjoner kalt. Men hvilken rekkefølge skal de bli innkalt? Det er hva den siste parameteren bestemmer. I W3C-spesifikasjonen ville vår klikkhendelse starte på kropp
og flytt ned kjeden til den når span # spare
; det er fangststadiet. Så går det fra span # spare
sikkerhetskopiere til kropp
; det er det boblende scenen. Dette er lett å huske, fordi bobler flyter oppover. Ikke alle hendelser boble; at Wikipedia-diagrammet vil fortelle deg hvilke som gjør og hvilke som ikke gjør det.
Så hvis fangstparameteren er satt til ekte
, hendelsen vil bli utløst på vei ned; hvis det er satt til falsk
, det vil bli utløst på vei opp.
Du har kanskje lagt merke til at så langt har alle mine eksempler satt til å falle, så hendelsen utløses i boblende scenen. Dette skyldes at Internet Explorer ikke har en fangstfase. I IE, hendelser bare boble.
IE har sin egen, proprietære måte å jobbe med hendelser på. Det bruker attachEvent
.
element.attachEvent ('onclick', runThisFunction);
Siden IE-hendelser bare bobler, trenger du ikke den tredje variabelen. De to første er de samme som med addEventListener
, med det store unntaket at IE krever at "på" prefiks for arrangementstypen. Selvfølgelig kan du tilordne flere hendelser av samme type til et enkelt element med denne modellen. For å fjerne hendelser, bruk detachEvent
.
element.detachEvent ('onclick', runThisFunction);
Hva om elementene dine ikke vil at foreldrene skal finne ut om hendelsene deres? Det er ikke vanskelig å gjemme seg. I IE bruker du cancelBubble
eiendom på hendelsesobjektet som blir sendt til den oppkalte funksjonen. For resten kan du bruke stopPropogation
metode, også på arrangementet objektet.
e.cancelBubble = true; hvis (e.stopPropagation) e.stopPropagation ();
De stopPropogation
Metoden vil også stoppe hendelser i sporene under fangststadiet.
Jeg ville være villig til å satse på at de fleste eiendommer på arrangementet vil gå ubrukt, men det er noen få utvalgte som du har funnet uvurderlig. La oss se på de få.
De mål
Egenskapen er det dypeste elementet som ble klikket. I bildet ovenfor kan du se at jeg klikket h1 # -knapp
. I IE kalles denne eiendommen srcElement
; å komme til denne eiendommen, gjør noe slikt:
var target = e.target || e.srcElement;
De currentTarget
eiendom er elementet som har hendelsen akkurat nå. I det skjermbildet, den currentTarget
er div # wrapper
. Dette betyr at jeg klikket h1 # -knapp
, men hendelsesobjektet ble logget på konsollen i funksjonen som ble kalt av div # wrapper
hendelse lytter.
Men dette vil kaste deg for en loop: IE har ikke en currentTarget-eiendom, eller noe som helst. Minnes om at IE ikke engang lar dette
lik elementet som utløser hendelsen, betyr det at vi ikke har mulighet til å få elementet som utløste hendelsen når det bobler opp (noe som betyr at en etterkommer av elementet ble klikket). Forvirret? Kanskje et eksempel vil hjelpe: hvis i Internet Explorer har vi denne HTML-koden ...
Knapp
... og denne hendelseshandleren ...
var par = document.getElementById ('foreldre'); parent.attachEvent ('onclick', doSomething);
... da, når vi klikker på span # barn
og hendelsen bobler opp til div # forelder
, Vi har ingen måte fra innsiden av funksjonen gjør noe
å komme på elementet (i dette tilfellet, div # forelder
) hendelsen ble utløst på.
Det finnes andre egenskaper på hendelsesobjektet som du finner nyttige, avhengig av saken. På et tastaturhendelse, (tast opp, keydown, tastetrykk), får du den nøkkelkode
og charCode
. Du vil kunne fortelle om brukeren holdt alt, skift eller ctrl (cmd) -tasten mens du trykker / klikker. Utforsk begivenhetsobjekter av ulike hendelser og se hva du må jobbe med!
Vi har kommet over to hovedproblemer i vår studie av hendelser så langt.
currentTarget
eiendom og dette
objekt refererer til vinduet objektet.For å løse disse problemene, la oss bygge to funksjoner med kryssbrowser-støtte, en for å koble til hendelser og en for å fjerne dem.
Vi begynner med addEvent
; her er rundt en:
var addEvent = funksjon (element, type, fn) if (element.attachEvent) element.attachEvent ('on' + type, fn); else element.addEventListener (type, fn, false);
Jeg tilordner en anonym funksjon til variabelen addEvent
av grunner vil du se om et minutt. Alt vi trenger å gjøre er å se om elementet har attachEvent
metode. Hvis det gjør det, er vi i IE, og vi bruker den metoden. Hvis ikke, kan vi bruke addEventListener
.
Dette gjør imidlertid ikke det faktum at vi ikke har mulighet til å få tilgang til arrangementets foreldreelement i IE. For å gjøre dette, gjør vi funksjonen et attributt på elementet; På den måten oppfattes det som en metode for elementet, og dette
vil være lik elementet. Ja, jeg vet, strålende, er det ikke? Vel, jeg kan ikke ta noen kreditt: Denne ideen kommer fra et blogginnlegg av John Resig.
var addEvent = funksjon (element, type, fn) if (element.attachEvent) element ['e' + type + fn] = fn; element [type + fn] = funksjon () element ['e' + type + fn] (window.event); element.attachEvent ('on' + type, element [type + fn]); else element.addEventListener (type, fn, false);
Den første ekstra linjen (element ['e' + type + fn] = fn;
) gjør funksjonen til en metode for elementet, slik at dette
vil nå lik elementet. Den andre linjen er en funksjon som utfører metoden, passerer i window.event-objektet. Dette sparer deg for ekstra trinn for å sjekke eventelementparameteren i funksjonen. Endelig merk at vi har endret funksjonsparameteren i attachEvent
metode til element [Type + fn]
.
Det løser våre to problemer. Vi kan nå bruke vår addEvent
Fungerer i alle nettlesere med så mye av en lignende opplevelse som mulig. Men det er litt optimzation som vi ønsker å lage.
Legg merke til at hver gang vår addEvent
funksjonen kalles, den sjekker for attachEvent
metode. Det er ingen grunn til at vi bør se etter dette mer enn en gang, uansett hvor mange hendelser vi ønsker å registrere. Vi kan bruke et greit triks som gjør at vi kan skrive på nytt addEvent
.
var addEvent = funksjon (el, type, fn) if (el.attachEvent) addEvent = funksjon (el, type, fn) el ['e' + type + fn] = fn; el [type + fn] = funksjon () el ['e' + type + fn] (window.event); ; el.attachEvent ('on' + type, el [type + fn]); else addEvent = funksjon (el, type, fn) el.addEventListener (type, fn, false); addEvent (el, type, fn);
Nå, hvis addEvent
Metoden er funnet, vi skriver om igjen addEvent
å bare inkludere IE-delene; Hvis ikke, vil vi bare inkludere de gode nettleserne.
Våre removeEvent
funksjonen vil være veldig lik:
var removeEvent = funksjon (element, type, fn) if (element.detachEvent) removeEvent = funksjon (element, type, fn) element.detachEvent ('on' + type, el [type + fn]); element [type + fn] = null; else removeEvent = funksjon (element, type, fn) element.removeEventListener (type, fn, false); removeEvent (element, type, fn);
Det er det for våre funksjonsfunksjoner på tvers av nettlesere. Det er en ting jeg ikke liker om dem, skjønt: funksjonene er ikke elementer av elementene; I stedet er elementet en parameter. Jeg vet at det bare er stil, men jeg liker det
btn.addEvent ('klikk', gjør dette);
bedre enn
addEvent (btn, 'klikk', gjør dette);
Vi kan gjøre dette ved å pakke inn våre funksjoner i dette:
var E = Element.prototype; E.addEvent = funksjon (type, fn) addEvent (dette, type, fn); E.removeEvent = funksjon (type, fn) removeEvent (dette, type, fn);
Dette vil fungere i alle moderne nettlesere, i tillegg til IE8; IE7 og IE6 choke på Element
. Det avhenger av publikum; ta det eller la det gå!
Nå som du vet alt om JavaScript-hendelser, ikke haste ut og fyll ditt neste prosjekt med hendelseslyttere. Hvis du har mange elementer som svarer på samme type arrangement (si, klikk), er det klokere å dra nytte av boblende. Du kan bare legge til en hendelselytter til et forfødselselement, til og med kroppen, og bruk egenskapen target / srcElement på hendelseobjektet for å finne ut hvilket dypere element som ble klikket. Dette kalles Event Delegation. Her er et ubrukelig eksempel:
Her er noen HTML:
Vi kan bruke hendelsesdelegasjonen til å håndtere klikk til hver enkelt li
:
funksjonsnavigering (e) var el = e.target || e.srcElement; bytte (el.id) case 'home': varsel ('gå hjem'); gå i stykker; saken 'portefølje': varsling ('sjekk ut mine produkter'); gå i stykker; saken 'om': varsel ('alle de motbydelige detaljer'); gå i stykker; saken 'kontakt': varsling ('Jeg er smigret du vil like å snakke'); gå i stykker; standard: varsel ('hvordan kom du hit?'); var nav = document.getElementById ('nav'); addEvent (nav, 'klikk', navigasjon);
Vi bruker en bryter / case-setning for å se på iden til det dypere klikket elementet. Da gjør vi noe tilsvarende.
Så nå kan du bruke JavaScript-hendelser med det beste av dem. Ha det gøy med det, og still spørsmål i kommentarene!