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.
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);
$ ( '# Container');
Deze functieaanroep vraagt de DOM naar het element met een ID kaart
van houder
, en maak een nieuwe jQuery
voorwerp.
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.
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.
. $ ( '# 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
.
var lis = document.querySelectorAll ('# container li');
querySelectorAll
zal terugkeren allemaal elementen die overeenkomen met de opgegeven CSS-selector.
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.
var lis = document.getElementById ('container'). getElementsByTagName ('li');
$ ('a'). on ('klik', fn);
In dit voorbeeld voegen we een toe Klik
gebeurtenislistener voor alle ankertags op de pagina.
[] .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
.
var anchors = document.getElementsbyTagName ('a'); addEvent (ankers, 'klik', fn);
$ ('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.
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
.
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
.
$ ( '# Box') addClass ( 'wrap.');
jQuery biedt een handige API voor het wijzigen van klassenamen op een reeks elementen.
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');
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?
. $ ( '# List') naast ();
jQuery volgende
methode retourneert het element dat onmiddellijk volgt op het huidige element in de ingepakte set.
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.
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.
$ (') .AppendTo ( 'body');
Naast het doorzoeken van de DOM, biedt jQuery ook de mogelijkheid om elementen te maken en te injecteren.
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';
$ (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.
document.addEventListener ('DOMContentLoaded', function () // have fun);
Gestandaardiseerd als onderdeel van HTML5, de DOMContentLoaded
gebeurtenis wordt geactiveerd zodra het document is voltooid.
// 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.
$ ('. 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.
[] .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.
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.
$ ()
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.
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!
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!
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.