Van jQuery tot JavaScript A Reference

Of we het nu leuk vinden of niet, meer en meer ontwikkelaars worden eerst via jQuery geïntroduceerd in de wereld van JavaScript. In veel opzichten zijn deze nieuwkomers de gelukkigen. Ze hebben toegang tot een overvloed aan nieuwe JavaScript-API's, die het proces van DOM-traversal (iets waarvoor veel mensen afhankelijk zijn van jQuery) aanzienlijk eenvoudiger maken. Helaas weten ze niet van deze API's!

In dit artikel nemen we een aantal verschillende jQuery-taken en converteren ze naar zowel modern als oud JavaScript.

Modern versus oud - Voor elk item in de onderstaande lijst vindt u de moderne, "coole kids" -manier om de taak te volbrengen, en de erfenis, "make old browsers happy" -versie. De keuze die u voor uw eigen projecten kiest, is grotendeels afhankelijk van uw bezoekers.


Voordat we beginnen

Houd er rekening mee dat sommige van de nalatenschap voorbeelden in dit artikel maken gebruik van een eenvoudige, cross-browser, Voeg evenement toe functie. Deze functie zorgt er eenvoudig voor dat zowel het door W3C aanbevolen gebeurtenismodel, addEventListener, en de erfenis van Internet Explorer attachEvent zijn genormaliseerd.

Dus wanneer ik verwijs addEvent (els, event, handler) in de oudere codefragmenten hieronder wordt naar de volgende functie verwezen.

var addEvent = (function () var filter = functie (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');

Deze functieaanroep vraagt ​​de DOM naar het element met een ID kaart van houder, en maak een nieuwe jQuery voorwerp.

Modern JavaScript

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

querySelector maakt deel uit van de Selectors API, die ons de mogelijkheid biedt om de DOM te bevragen met behulp van de CSS-selectors die we al kennen.

Deze specifieke methode retourneert het eerste element dat overeenkomt met de geselecteerde selector.

nalatenschap

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

Besteed speciale aandacht aan hoe u naar het element verwijst. Tijdens gebruik getElementById, je geeft de waarde alleen door, terwijl je met querySelector, er wordt een CSS-selector verwacht.


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

Deze keer jagen we niet op een enkel element; in plaats daarvan vangen we een willekeurig aantal lijstitems op die afstammen van #houder.

Modern JavaScript

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

querySelectorAll zal terugkeren allemaal elementen die overeenkomen met de opgegeven CSS-selector.

Selector Beperkingen

Hoewel vrijwel alle relevante browsers de Selectors API ondersteunen, zijn de specifieke CSS-kiezers die u doorgeeft nog steeds beperkt tot de mogelijkheden van de browser. Vertaling: Internet Explorer 8 ondersteunt alleen CSS 2.1 selectors.

nalatenschap

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

3 - $ ('a'). on ('klik', fn);

In dit voorbeeld voegen we een toe Klik gebeurtenislistener voor alle ankertags op de pagina.

Modern JavaScript

[] .forEach.call (document.querySelectorAll ('a'), functie (el) el.addEventListener ('klik', functie () // anchor is aangeklikt, false););

Het bovenstaande fragment ziet er eng uit, maar het is niet slecht. Omdat querySelectorAll geeft een statisch terug nodelist in plaats van een reeks, we kunnen geen directe toegang krijgen tot methoden, zoals forEach. Dit wordt verholpen door te bellen forEach op de reeks object en de resultaten van querySelectorAll zoals deze.

nalatenschap

var anchors = document.getElementsbyTagName ('a'); addEvent (ankers, 'klik', fn);

4 - $ ('ul'). on ('klik', 'a', fn);

Ahh - dit voorbeeld is iets anders. Deze keer maakt het jQuery-fragment gebruik van gebeurtenisafvaardiging. De Klik listener wordt toegepast op alle niet-geordende lijsten, maar de callback-functie wordt alleen geactiveerd als het doel (waarop de gebruiker specifiek heeft geklikt) een ankertag is.

Modern JavaScript

document.addEventListener ('klik', functie (e) if (e.target.matchesSelector ('ul a')) // proceed, false);

Technisch gezien is deze vanilla JavaScript-methode niet hetzelfde als het jQuery-voorbeeld. In plaats daarvan verbindt het de gebeurtenislistener rechtstreeks met de document. Vervolgens wordt het nieuwe gebruikt matchesSelector methode om te bepalen of de doelwit - het knooppunt waarop is geklikt - komt overeen met de opgegeven selector. Op deze manier voegen we een luisteraar voor één gebeurtenis toe, in plaats van veel.

Houd er rekening mee dat, op het moment van schrijven, alle browsers worden geïmplementeerd matchesSelector via hun eigen respectievelijke voorvoegsels: mozMatchesSelector, webkitMatchesSelector, etc. Om de methode te normaliseren, zou je kunnen schrijven:

var-overeenkomsten; (functie (doc) matches = doc.matchesSelector || doc.webkitMatchesSelector || doc.mozMatchesSelector || doc.oMatchesSelector || doc.msMatchesSelector;) (document.documentElement); document.addEventListener ('klik', functie (e) if (matches.call (e.target, 'ul a')) // proceed, false);

Met deze techniek, in Webkit, zullen wedstrijden verwijzen naar webkitMatchesSelector, en, in Mozilla, mozMatchesSelector.

nalatenschap

var uls = document.getElementsByTagName ('ul'); addEvent (uls, 'klik', function () var target = e.target || e.srcElement; if (target && target.nodeName === 'A') // proceed);

Als een fallback, bepalen we of de nodeName eigenschap (de naam van het doelelement) is gelijk aan onze gewenste zoekopdracht. Besteed speciale aandacht aan het feit dat oudere versies van Internet Explorer soms volgens hun eigen regels spelen - een beetje zoals het kind dat tijdens de lunch aan het spelen is. U krijgt geen toegang doelwit rechtstreeks van de evenement voorwerp. In plaats daarvan wilt u zoeken naar event.srcElement.


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

jQuery biedt een handige API voor het wijzigen van klassenamen op een reeks elementen.

Modern JavaScript

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

Deze nieuwe techniek gebruikt de nieuwe classlist API voor toevoegen, verwijderen, en toggle klassenamen.

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

nalatenschap

var box = document.getElementById ('box'), hasClass = function (el, cl) var regex = new RegExp ('(?: \\ s | ^)' + cl + '(?: \\ s | $ )); retour !! el.className.match (regex); , addClass = function (el, cl) el.className + = "+ cl;, removeClass = function (el, cl) var regex = new RegExp ('(?: \\ s | ^)' + cl + '(?: \\ s | $)'); el.className = el.className.replace (regex, "); , toggleClass = function (el, cl) hasClass (el, cl)? removeClass (el, cl): addClass (el, cl); ; addClass (box, 'drago'); removeClass (box, 'drago'); toggleClass (box, 'drago'); // als het element geen klasse van 'drago' heeft, voeg er dan een toe.

De fallback-techniek vereist nog net iets meer werk, ja?


6 - . $ ( '# List') naast ();

jQuery volgende methode retourneert het element dat onmiddellijk volgt op het huidige element in de ingepakte set.

Modern JavaScript

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

nextElementSibling zal specifiek naar de volgende verwijzen element knooppunt, in plaats van een knoop (tekst, opmerking, element). Helaas ondersteunen Internet Explorer 8 en lager het niet.

nalatenschap

var list = document.getElementById ('list'), next = list.nextSibling; // we willen het volgende elementknooppunt ... geen tekst. while (next.nodeType> 1) next = next.nextSibling;

Er zijn een paar manieren om dit te schrijven. In dit voorbeeld detecteren we de nodeType van het knooppunt dat het opgegeven element volgt. Het kan een tekst, een element of zelfs een opmerking zijn. Omdat we specifiek het volgende element nodig hebben, verlangen we naar een nodeType van 1. Als next.nodeType retourneert een getal groter dan 1, we moeten het overslaan en doorgaan, omdat het waarschijnlijk een tekstknooppunt is.


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

Naast het doorzoeken van de DOM, biedt jQuery ook de mogelijkheid om elementen te maken en te injecteren.

Modern JavaScript

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

Er is niets moderns aan dit voorbeeld; het is hoe we het proces van het creëren en injecteren van elementen in de DOM voor een lange, lange tijd hebben volbracht.

Je zult waarschijnlijk inhoud aan het element moeten toevoegen, in welk geval je het kunt gebruiken innerHTML, of createTextNode.

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

8 - $ (Document) .ready (fn)

jQuery document.ready methode is ongelooflijk handig. Hiermee kunnen we beginnen met het uitvoeren van code zo snel mogelijk nadat de DOM is geladen.

Modern JavaScript

document.addEventListener ('DOMContentLoaded', function () // have fun);

Gestandaardiseerd als onderdeel van HTML5, de DOMContentLoaded gebeurtenis wordt geactiveerd zodra het document is voltooid.

nalatenschap

// http://dustindiaz.com/smallest-domready-ever function ready (cb) /in/.test(document.readyState) // in = laden? setTimeout ('ready (' + cb + ')', 9): cb ();  gereed (functie () // iets van de DOM halen);

De fallback-oplossing, elke negen milliseconden, detecteert de waarde van document.readyState. Als "laden" wordt geretourneerd, is het document nog niet volledig geparseerd (/in/.test (). Als dat eenmaal gebeurd is, document.readyState is gelijk aan "voltooid", waarna de callback-functie van de gebruiker wordt uitgevoerd.


9 - $ ('. box'). css ('color', 'red');

Voeg indien mogelijk altijd een toe klasse naar een element, wanneer u een speciale styling nodig heeft. Soms wordt de stijl echter dynamisch bepaald, in welk geval deze als een attribuut moet worden ingevoegd.

Modern JavaScript

[] .forEach.call (document.querySelectorAll ('. box'), functie (el) el.style.color = 'red'; // of voeg een klasse toe);

Nogmaals, we gebruiken de [] .ForEach.call () techniek om door alle elementen te filteren met een klasse van doos, en maak ze rood, via de stijl voorwerp.

nalatenschap

var box = document.getElementsByClassName ('box'), // verwijs naar voorbeeld # 10 hieronder voor een cross-browseroplossing i = box.length; while (i--> 0 && (box [i] .style.color = 'red'));

Deze keer worden we een beetje lastig met de terwijl lus. Ja, het is een beetje sneaky, toch? In wezen bootsen we:

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

Omdat we echter maar één actie hoeven uit te voeren, kunnen we een paar regels opslaan. Merk op dat de leesbaarheid veel belangrijker is dan het opslaan van twee regels - vandaar mijn "snarky" -referentie. Niettemin is het altijd leuk om te zien hoe gecondenseerd je lussen kunt maken. Wij zijn ontwikkelaars; we doen dit soort dingen voor de lol! Hoe dan ook, voel je vrij om vast te houden aan de voor verklaring versie.


10 - $ ()

Het is duidelijk dat het niet onze bedoeling is om de volledige jQuery API te repliceren. Typisch, voor niet-jQuery-projecten, de $ of $$ functie wordt gebruikt als afkorting voor het ophalen van een of meer elementen uit de DOM.

Modern JavaScript

var $ = function (el) return document.querySelectorAll (el); ; // Gebruik = $ ('. Box');

Let erop dat $ is gewoon een aanwijzer van één teken naar document.querySelector. Het bespaart tijd!

nalatenschap

if (! document.getElementsByClassName) document.getElementsByClassName = function (cl, tag) var els, matches = [], i = 0, len, regex = new RegExp ('(?: \\ s | ^)' + cl + '(?: \\ s | $)'); // Als er geen tagnaam is opgegeven, // moeten we ELK element uit de DOM halen els = document.getElementsByTagName (tag || "*"); als (! els [0]) false retourneert; 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

Helaas is de oude methode niet zo minimaal. Eerlijk gezegd, zou u op dit moment een bibliotheek moeten gebruiken. jQuery is sterk geoptimaliseerd voor het werken met de DOM, daarom is het zo populair! Het bovenstaande voorbeeld zal zeker werken, maar het ondersteunt geen complexe CSS-selectors in oudere browsers; die taak is gewoon een klein beetje ingewikkelder!


Samenvatting

Het is belangrijk voor mij om op te merken dat ik je niet aanmoedig om jQuery te verlaten. Ik gebruik het in bijna al mijn projecten. Dat gezegd hebbende, wees niet altijd bereid om abstracties te omarmen zonder een beetje tijd te nemen om de onderliggende code te onderzoeken.

Ik wil graag dat dit bericht als een soort levend document wordt gebruikt. Als je een eigen versie hebt (of verbeteringen / verduidelijkingen voor mijn voorbeelden), laat hieronder een reactie achter en ik zal dit bericht sporadisch bijwerken met nieuwe items. Voeg deze pagina toe als bladwijzer! Ten slotte zou ik graag een hat-tip sturen naar deze reeks voorbeelden, die de aanzet vormde voor dit bericht.