Fra jQuery til JavaScript En referanse

Enten vi liker det eller ikke, blir flere og flere utviklere introdusert til verden av JavaScript gjennom jQuery først. På mange måter er disse nykommerne de heldige. De har tilgang til en mengde nye JavaScript-APIer, noe som gjør prosessen med DOM-traversal (noe som mange folk er avhengige av jQuery for) betydelig enklere. Dessverre vet de ikke om disse APIene!

I denne artikkelen tar vi en rekke vanlige jQuery-oppgaver, og konverterer dem til både moderne og eldre JavaScript.

Moderne vs Legacy - For hvert element i listen nedenfor finner du den moderne "cool kids" -veien for å oppnå oppgaven, og arven, "gjør gamle nettlesere glade" -versjonen. Valget du velger for dine egne prosjekter, vil i stor grad avhenge av dine besøkende.


Før vi begynner

Vær oppmerksom på at noen av arven eksempler i denne artikkelen vil gjøre bruk av en enkel, kryssbrowser, addEvent funksjon. Denne funksjonen sikrer ganske enkelt at både den W3C-anbefalte hendelsesmodellen, addEventListener, og Internet Explorer arv attachEvent er normalisert.

Så når jeg refererer til addEvent (els, event, handler) i arvenes kodestykker nedenfor, blir følgende funksjon referert til.

var addEvent = (funksjon () var filter = funksjon (el, type, fn) for (var i = 0, len = el.length; i < len; i++ )  addEvent(el[i], type, fn);  ; if ( document.addEventListener )  return function (el, type, fn)  if ( el && el.nodeName || el === window )  el.addEventListener(type, fn, false);  else if (el && el.length)  filter(el, type, fn);  ;  return function (el, type, fn)  if ( el && el.nodeName || el === window )  el.attachEvent('on' + type, function ()  return fn.call(el, window.event); );  else if ( el && el.length )  filter(el, type, fn);  ; )(); // usage addEvent( document.getElementsByTagName('a'), 'click', fn);

1 - $ ( '# Container');

Denne funksjonen samtalen vil spørre DOM for elementet med en id av container, og opprett en ny jQuery gjenstand.

Moderne JavaScript

var container = document.querySelector ('# container');

querySelector er en del av Selectors API, som gir oss muligheten til å spørre DOM ved hjelp av CSS selectors som vi allerede er kjent med.

Denne spesielle metoden vil returnere det første elementet som samsvarer med den valgte väljeren.

Legacy

var container = document.getElementById ('container');

Vær særlig oppmerksom på hvordan du refererer til elementet. Når du bruker getElementById, Du overfører verdien alene, mens, med querySelector, en CSS velger er forventet.


2 - . $ ( '# Container') finne ( 'li');

Denne gangen er vi ikke på jakt etter et enkelt element; I stedet fanger vi et hvilket som helst antall listeposter som er etterkommere av #container.

Moderne JavaScript

var lis = document.querySelectorAll ('# container li');

querySelectorAll vil returnere alle elementer som samsvarer med den angitte CSS-väljeren.

Valgbegrensninger

Mens nesten alle relevante nettlesere støtter Selectors API, vil de spesifikke CSS-valgene du passerer, fremdeles være begrenset til nettleserens evne. Oversettelse: Internet Explorer 8 støtter bare CSS 2.1-valg.

Legacy

var lis = document.getElementById ('container'). getElementsByTagName ('li');

3 - $ ('a'). på ('klikk', fn);

I dette eksemplet knytter vi en klikk hendelselytter til alle ankerkoder på siden.

Moderne JavaScript

[] .forEach.call (document.querySelectorAll ('a'), funksjon (el) el.addEventListener ('klikk', funksjon () // anker ble klikket, falsk););

Ovennevnte kutt ser skummelt ut, men det er ikke så ille. Fordi querySelectorAll returnerer en statisk NodeList heller enn en Array, Vi kan ikke direkte få tilgang til metoder, som for hver. Dette løses ved å ringe for hverArray objekt, og passerer resultatene av querySelectorAll som dette.

Legacy

var ankre = document.getElementsbyTagName ('a'); addEvent (ankre, klikk ", fn);

4 - $ ('ul'). på ('klikk', 'a', fn);

Ahh - dette eksemplet er litt annerledes. Denne gangen bruker jQuery-kuttet hendelsesdelegasjon. De klikk lytteren blir brukt på alle uordnede lister, men tilbakekallingsfunksjonen vil bare brenne hvis målet (det som brukeren klikket spesielt på) er et ankermerke.

Moderne JavaScript

document.addEventListener ('klikk', funksjon (e) hvis (e.target.matchesSelector ('ul a')) // fortsett, feil);

Teknisk er denne vanilla JavaScript-metoden ikke den samme som jQuery-eksemplet. I stedet er det knyttet hendelseslytteren direkte til dokument. Den bruker deretter den nye matchesSelector metode for å avgjøre om mål - noden som ble klikket - samsvarer med den valgte väljeren. På denne måten knytter vi en enkelt hendelse lytter, i stedet for mange.

Vær oppmerksom på at alle nettlesere implementerer på tidspunktet for denne skrivingen matchesSelector via sine respektive prefikser: mozMatchesSelector, webkitMatchesSelector, etc. For å normalisere metoden kan man skrive:

var kamper; (funksjon (doc) matches = doc.matchesSelector || doc.webkitMatchesSelector || doc.mozMatchesSelector || doc.oMatchesSelector || doc.msMatchesSelector;) (document.documentElement); document.addEventListener ('klikk', funksjon (e) hvis (matches.call (e.target, 'ul a')) // fortsett, falsk);

Med denne teknikken, i Webkit, vil kamper referere til webkitMatchesSelector, og i Mozilla, mozMatchesSelector.

Legacy

var uls = document.getElementsByTagName ('ul'); addEvent (uls, 'klikk', funksjon () var target = e.target || e.srcElement; hvis (mål && target.nodeName === 'A') // fortsett);

Som en tilbakebetaling bestemmer vi om nodename Egenskapen (navnet på målelementet) er lik vår forespurte forespørsel. Vær særlig oppmerksom på at eldre versjoner av Internet Explorer noen ganger spiller etter egne regler - som for eksempel barnet som spiser play-doh i lunsjtid. Du vil ikke kunne få tilgang mål direkte fra begivenhet gjenstand. I stedet vil du se etter event.srcElement.


5 - $ ( '# Box') addClass ( 'wrap.');

jQuery gir en nyttig API for å endre klassenavn på et sett med elementer.

Moderne JavaScript

document.querySelector ( '# box') classList.add ( 'wrap.');

Denne nye teknikken bruker den nye classList API til Legg til, fjerne, og veksle klassenavn.

var container = document.querySelector ('# box'); container.classList.add ( 'wrap'); container.classList.remove ( 'wrap'); container.classList.toggle ( 'wrap');

Legacy

var boks = document.getElementById ('boks'), hasClass = funksjon (el, cl) var regex = nytt RegExp ('(?: \\ s | ^)' + cl + '(?: \\ s | $ ) '); returnere! el.className.match (regex); , addClass = funksjon (el, cl) el.className + = "+ cl;, removeClass = funksjon (el, cl) var regex = ny RegExp ('(?: \\ s | ^)' + cl + '(?: \\ s | $)'); el.className = el.className.replace (regex, "); , toggleClass = funksjon (el, cl) hasClass (el, cl)? removeClass (el, cl): addClass (el, cl); ; addClass (boks, 'drago'); removeClass (boks, 'drago'); toggleClass (boks, 'drago'); // hvis elementet ikke har en klasse av 'drago', legg til en.

Fallback-teknikken krever bare litt mer arbeid, ay?


6 - . $ ( '# Listen') neste ();

jQuery neste Metoden vil returnere elementet som umiddelbart følger det nåværende elementet i det pakkede settet.

Moderne JavaScript

var neste = document.querySelector ('# list'). nextElementSibling; // IE9

nextElementSibling vil referere spesifikt til det neste element node, snarere enn noen node (tekst, kommentar, element). Dessverre støtter ikke Internet Explorer 8 og under det.

Legacy

var list = document.getElementById ('liste'), next = list.nextSibling; // vi vil ha neste elementskode ... ikke tekst. mens (next.nodeType> 1) next = next.nextSibling;

Det er et par måter å skrive dette på. I dette eksemplet oppdager vi Nodetype av noden som følger det angitte elementet. Det kan være tekst, element eller til og med en kommentar. Som vi spesielt trenger det neste elementet, ønsker vi a Nodetype av 1. Hvis next.nodeType returnerer et tall som er større enn 1, vi burde hoppe over det og fortsette, da det er sannsynligvis en tekstknute.


7 - $ ('
') .AppendTo (' body ");

I tillegg til å spørre DOM, tilbyr jQuery også muligheten til å lage og injisere elementer.

Moderne JavaScript

var div = document.createElement ('div'); div.id = 'box'; document.body.appendChild (div);

Det er ikke noe moderne om dette eksempelet; Det er hvordan vi har oppnådd prosessen med å lage og injisere elementer i DOM i lang, lang tid.

Du må sannsynligvis legge til innhold i elementet, i så fall kan du enten bruke innerhtml, eller createTextNode.

div.appendChild (document.createTextNode ('wacka wacka')); // eller div.innerHTML = 'wacka wacka';

8 - $ (Document) .ready (fn)

jQuery document.ready metoden er utrolig praktisk. Det tillater oss å begynne å utføre kode så snart som mulig etter at DOM er lastet inn.

Moderne JavaScript

document.addEventListener ('DOMContentLoaded', funksjon () // ha det gøy);

Standardisert som en del av HTML5, the DOMContentLoaded hendelsen vil brenne så snart dokumentet er fullført, analysert.

Legacy

// http://dustindiaz.com/smallest-domready-function ready (cb) /in/.test(document.readyState) // in = loadINg? setTimeout ('ready (' + cb + ')', 9): cb ();  klar (funksjon () // ta tak i noe fra DOM);

Fallback-løsningen, hver ni millisekunder, vil oppdage verdien av document.readyState. Hvis "loading" returneres, har dokumentet ennå ikke blitt fullstendig analysert (/in/.test (). En gang den har, skjønt, document.readyState vil være lik "fullført", på hvilket tidspunkt brukerens tilbakeringingsfunksjon utføres.


9 - $ ('.boks'). css ('farge', 'rød');

Hvis mulig, legg alltid til en klasse til et element når du trenger å gi spesiell styling. Men noen ganger vil stylingen bli bestemt dynamisk, i så fall må den settes inn som et attributt.

Moderne JavaScript

[] .forEach.call (document.querySelectorAll ('.box'), funksjon (el) el.style.color = 'rød'; // eller legg til en klasse);

Nok en gang bruker vi [] .ForEach.call () teknikk for å filtrere gjennom alle elementene med en klasse av eske, og gjør dem røde, via stil gjenstand.

Legacy

var box = document.getElementsByClassName ('box'), // referer til eksempel # 10 nedenfor for en kryssbrowser løsning i = box.length; mens (jeg--> 0 && (boks [i] .style.color = 'rød'));

Denne gangen blir vi litt vanskelige med samtidig som sløyfe. Ja, det er litt snarky, ikke sant? I hovedsak mimler vi:

var i = 0, len; for (len = box.length; i < len; i++ )  box[i].style.color = 'red'; 

Men da vi bare trenger å utføre en enkelt handling, kan vi lagre et par linjer. Merk at lesbarhet er langt viktigere enn å lagre to linjer - derav min "snarky" referanse. Likevel er det alltid morsomt å se hvordan kondensert du kan lage sløyfer. Vi er utviklere; Vi gjør slike ting for moro skyld! Uansett, vær så snill å holde fast ved til uttalelsesversjon.


10 - $ ()

Det er klart at vår hensikt er ikke å gjenskape hele jQuery API. Vanligvis for ikke-jQuery-prosjekter, $ eller $$ funksjonen brukes som stenografi for å hente ett eller flere elementer fra DOM.

Moderne JavaScript

var $ = funksjon (el) return document.querySelectorAll (el); ; // Bruk = $ ('. Boks');

Legg merke til det $ er rett og slett et tegn på en tegn til document.querySelector. Det sparer tid!

Legacy

hvis (! document.getElementsByClassName) document.getElementsByClassName = funksjon (kl, tag) var els, matches = [], i = 0, len, regex = nytt RegExp ('(?: \\ s | ^)' + cl + '(?: \\ s | $)'); // Hvis ikke noe navn er oppgitt, // vi må ta tak i EVERY element fra DOM els = document.getElementsByTagName (tag || "*"); hvis (! els [0]) returnerer falsk; for (len = els.length; i < len; i++ )        if ( els[i].className.match(regex) )           matches.push( els[i]);               return matches; // an array of elements that have the desired classname ;    // Very simple implementation. We're only checking for an id, class, or tag name. // Does not accept CSS selectors in pre-querySelector browsers. var $ = function(el, tag)     var firstChar = el.charAt(0);      if ( document.querySelectorAll ) return document.querySelectorAll(el);      switch ( firstChar )        case "#":          return document.getElementById( el.slice(1) );       case ".":          return document.getElementsByClassName( el.slice(1), tag );       default:          return document.getElementsByTagName(el);     ; // Usage $('#container'); $('.box'); // any element with a class of box $('.box', 'div'); // look for divs with a class of box $('p'); // get all p elements

Dessverre er arvmetoden ikke helt så minimal. Ærlig, på dette tidspunktet bør du bruke et bibliotek. jQuery er svært optimalisert for å jobbe med DOM, og det er derfor det er så populært! Eksemplet ovenfor vil sikkert fungere, men det støtter ikke komplekse CSS-selektorer i eldre nettlesere; den oppgaven er bare litt mer komplisert!


Sammendrag

Det er viktig for meg å merke seg at jeg ikke oppfordrer deg til å forlate jQuery. Jeg bruker det i nesten alle mine prosjekter. Når det er sagt, ikke alltid være villig til å omfavne abstraksjoner uten å ta litt tid på å undersøke den underliggende koden.

Jeg vil gjerne at dette innlegget skal tjene som et levende dokument, av forskjellige slag. Hvis du har noen av dine egne (eller forbedringer / avklaringer for mine eksempler), legg igjen en kommentar nedenfor, og jeg vil sporadisk oppdatere denne innleggingen med nye elementer. Bookmark denne siden nå! Til slutt vil jeg sende et hat-tips til dette settet med eksempler, som tjente som drivkraft for dette innlegget.