Ob es uns gefällt oder nicht, immer mehr Entwickler werden zuerst über jQuery in die Welt von JavaScript eingeführt. In vielerlei Hinsicht sind diese Neuankömmlinge die Glücklichen. Sie haben Zugriff auf eine Fülle neuer JavaScript-APIs, die den Prozess der DOM-Traversierung (etwas, für das viele Leute auf jQuery angewiesen sind) erheblich vereinfachen. Leider wissen sie nichts über diese APIs!
In diesem Artikel nehmen wir eine Vielzahl gängiger jQuery-Aufgaben und konvertieren sie in modernes und älteres JavaScript.
Modern vs. Legacy – Für jedes Element in der folgenden Liste finden Sie die moderne, „coole Kinder“-Methode, um die Aufgabe zu erfüllen, und die Legacy-Version, „die alte Browser glücklich macht“. Die Wahl, die Sie für Ihre eigenen Projekte wählen, hängt weitgehend von Ihren Besuchern ab.
Bevor wir anfangen
Bitte beachten Sie, dass einige der Legacy -Beispiele in diesem Artikel eine einfache browserübergreifende addEvent
Funktion verwenden. Diese Funktion stellt einfach sicher, dass sowohl das vom W3C empfohlene Ereignismodell als auch die Vorgängerversion addEventListener
von Internet Explorer attachEvent
normalisiert werden.
Wenn ich also addEvent(els, event, handler)
in den Legacy-Codeausschnitten unten darauf verweise, wird auf die folgende Funktion verwiesen.
var addEvent = (Funktion () { var filter = function(el, typ, fn) { for ( var i = 0, len = el.länge; i < len; i++ ) { addEvent(el[i], type, fn); } }; if ( document.addEventListener ) { Rückgabefunktion (el, type, fn) { if ( el && el.nodeName || el === Fenster ) { el.addEventListener (Typ, fn, falsch); } else if (el && el.länge) { filter(el, typ, fn); } }; } Rückgabefunktion (el, type, fn) { if ( el && el.nodeName || el === Fenster ) { el.attachEvent('on' + type, function () { return fn.call(el, window.event); }); } else if ( el && el.länge ) { filter(el, typ, fn); } }; })(); // Verwendungszweck addEvent( document.getElementsByTagName('a'), 'click', fn);
1 -$('#container');
Dieser Funktionsaufruf fragt das DOM nach dem Element mit einem id
von ab container
und erstellt ein neues jQuery
Objekt.
Modernes JavaScript
var container = document.querySelector('#container');
querySelector
ist Teil der Selectors API , die uns die Möglichkeit bietet, das DOM mit den uns bereits vertrauten CSS-Selektoren abzufragen.
Diese spezielle Methode gibt das erste Element zurück, das mit dem übergebenen Selektor übereinstimmt.
Vermächtnis
var container = document.getElementById('container');
Achten Sie besonders darauf, wie Sie auf das Element verweisen. Bei Verwendung getElementById
von übergeben Sie den Wert alleine, während bei Verwendung querySelector
ein CSS-Selektor erwartet wird.
2 -$('#container').find('li');
Dieses Mal jagen wir nicht nach einem einzelnen Element; Stattdessen erfassen wir eine beliebige Anzahl von Listenelementen, die Nachkommen von sind #container
.
Modernes JavaScript
var lis = document.querySelectorAll('#container li');
querySelectorAll
gibt alle Elemente zurück, die mit dem angegebenen CSS-Selektor übereinstimmen.
Auswahlbeschränkungen
Während fast alle relevanten Browser die Selektoren-API unterstützen, sind die spezifischen CSS-Selektoren, die Sie übergeben, immer noch auf die Fähigkeiten des Browsers beschränkt. Übersetzung: Internet Explorer 8 unterstützt nur CSS 2.1-Selektoren.
Vermächtnis
var lis = document.getElementById('container').getElementsByTagName('li');
3 - $('a').on('click', fn);
In diesem Beispiel hängen wir einen click
Ereignis-Listener an alle Anker-Tags auf der Seite an.
Modernes JavaScript
[].forEach.call( document.querySelectorAll('a'), function(el) { el.addEventListener('click', function() { // Anker wurde angeklickt }, falsch); });
Das obige Snippet sieht beängstigend aus, aber es ist nicht so schlimm. Da statt querySelectorAll
eines ein statisches zurückgegeben wird, können wir nicht direkt auf Methoden wie zugreifen . Dies wird behoben, indem das Objekt aufgerufen und die Ergebnisse von as übergeben werden .NodeList
Array
forEach
forEach
Array
querySelectorAll
this
Vermächtnis
varanker = document.getElementsbyTagName('a'); addEvent(anker, 'click', fn);
4 -$('ul').on('click', 'a', fn);
Ahh - dieses Beispiel ist etwas anders. Dieses Mal verwendet das jQuery-Snippet die Ereignisdelegierung. Der click
Listener wird auf alle ungeordneten Listen angewendet, die Callback-Funktion wird jedoch nur ausgelöst, wenn das Ziel (auf das der Benutzer speziell geklickt hat) ein Anchor-Tag ist.
Modernes JavaScript
document.addEventListener('click', function(e) { if ( e.target.matchesSelector('ul a') ) { // Vorgehen } }, falsch);
Technisch gesehen ist diese Vanilla-JavaScript-Methode nicht mit dem jQuery-Beispiel identisch. Stattdessen wird der Ereignis-Listener direkt an die document
. Dann verwendet es die neue matchesSelector
Methode, um zu bestimmen, ob der target
Knoten, auf den geklickt wurde, mit dem bereitgestellten Selektor übereinstimmt. Auf diese Weise hängen wir einen einzelnen Ereignis-Listener an und nicht viele.
Bitte beachten Sie, dass zum Zeitpunkt dieses Schreibens alle Browser matchesSelector
über ihre eigenen jeweiligen Präfixe implementieren: mozMatchesSelector
, webkitMatchesSelector
, usw. Um die Methode zu normalisieren, könnte man schreiben:
var passt; (Funktion (doc) { Übereinstimmungen = doc.matchesSelector || doc.webkitMatchesSelector || doc.mozMatchesSelector || doc.oMatchesSelector || doc.msMatchesSelector; })(dokument.dokumentElement); document.addEventListener('click', function(e) { if (matches.call( e.target, 'ul a') ) { // Vorgehen } }, falsch);
Bei dieser Technik beziehen sich Übereinstimmungen in Webkit auf
webkitMatchesSelector
, und in Mozilla aufmozMatchesSelector
.
Vermächtnis
var uls = document.getElementsByTagName('ul'); addEvent(uls, 'click', function() { var Ziel = e.Ziel || e.srcElement; if ( Ziel && Ziel.Knotenname === 'A' ) { // Vorgehen } });
Als Fallback bestimmen wir, ob die nodeName
Eigenschaft (der Name des Zielelements) unserer gewünschten Abfrage entspricht. Achten Sie besonders darauf, dass ältere Versionen des Internet Explorers manchmal nach ihren eigenen Regeln spielen – ähnlich wie das Kind, das in der Mittagspause Knete isst. target
Sie können nicht direkt über das event
Objekt darauf zugreifen . Stattdessen sollten Sie nach suchen event.srcElement
.
5 -$('#box').addClass('wrap');
jQuery bietet eine hilfreiche API zum Ändern von Klassennamen für eine Reihe von Elementen.
Modernes JavaScript
document.querySelector('#box').classList.add('wrap');
Diese neue Technik verwendet die neue classList
API für add
, remove
und toggle
Klassennamen.
var container = document.querySelector('#box'); container.classList.add('wrap'); container.classList.remove('wrap'); container.classList.toggle('wrap');
Vermächtnis
var box = document.getElementById('box'), hasClass = Funktion (el, cl) { var regex = new RegExp('(?:\\s|^)' + cl + '(?:\\s|$)'); return !!el.className.match(regex); }, addClass = Funktion (el, cl) { el.klassenname += ' ' + cl; }, removeClass = Funktion (el, cl) { var regex = new RegExp('(?:\\s|^)' + cl + '(?:\\s|$)'); el.className = el.className.replace(regex, ' '); }, toggleClass = Funktion (el, cl) { hasClass(el, cl) ? removeClass(el, cl) : addClass(el, cl); }; addClass(box, 'drago'); removeClass(box, 'drago'); toggleClass(box, 'drago'); // wenn das Element keine Klasse von 'drago' hat, füge eine hinzu.
Die Fallback-Technik erfordert nur ein bisschen mehr Arbeit, oder?
6 -$('#list').next();
Die Methode von jQuery gibt next
das Element zurück, das unmittelbar auf das aktuelle Element in der umschlossenen Menge folgt.
Modernes JavaScript
var next = document.querySelector('#list').nextElementSibling; // IE9
nextElementSibling
bezieht sich speziell auf den nächsten Elementknoten und nicht auf irgendeinen Knoten (Text, Kommentar, Element). Leider wird dies von Internet Explorer 8 und darunter nicht unterstützt.
Vermächtnis
var list = document.getElementById('list'), next = list.nextSibling; // Wir wollen den nächsten Elementknoten...nicht Text. while ( next.nodeType > 1 ) next = next.nextSibling;
Es gibt ein paar Möglichkeiten, dies zu schreiben. In diesem Beispiel erkennen wir das nodeType
des Knotens, der auf das angegebene Element folgt. Es kann Text, Element oder sogar ein Kommentar sein. Da wir speziell das nächste Element benötigen, wünschen wir uns ein nodeType
von 1
. Wenn next.nodeType
eine Zahl größer als zurückgegeben 1
wird, sollten wir sie überspringen und weitermachen, da es sich wahrscheinlich um einen Textknoten handelt.
7 -$('<div id=box></div>').appendTo('body');
Neben der Abfrage des DOM bietet jQuery auch die Möglichkeit, Elemente zu erstellen und einzufügen.
Modernes JavaScript
var div = document.createElement('div'); div.id = 'Box'; document.body.appendChild(div);
An diesem Beispiel ist nichts Modernes; So haben wir den Prozess des Erstellens und Einfügens von Elementen in das DOM für eine lange, lange Zeit durchgeführt.
Wahrscheinlich müssen Sie dem Element Inhalt hinzufügen, in diesem Fall können Sie entweder innerHTML
, oder verwenden createTextNode
.
div.appendChild( document.createTextNode('wacka wacka') ); // oder div.innerHTML = 'wacka wacka';
8 -$(document).ready(fn)
Die Methode von jQuery document.ready
ist unglaublich praktisch. Es ermöglicht uns, so schnell wie möglich mit der Ausführung von Code zu beginnen, nachdem das DOM geladen wurde.
Modernes JavaScript
document.addEventListener('DOMContentLoaded', function() { // habe Spaß });
Standardisiert als Teil von HTML5, wird das DOMContentLoaded
Ereignis ausgelöst, sobald das Dokument vollständig geparst wurde.
Vermächtnis
// http://dustindiaz.com/smallest-domready-ever Funktion bereit (cb) { /in/.test(document.readyState) // in = laden ? setTimeout('bereit('+cb+')', 9) : cb(); } bereit(funktion() { // Etwas aus dem DOM holen });
Die Fallback-Lösung erkennt alle neun Millisekunden den Wert von document.readyState
. Wenn "loading" zurückgegeben wird, wurde das Dokument noch nicht vollständig geparst ( /in/.test()
. Sobald es jedoch document.readyState
"complete" ist, wird die Callback-Funktion des Benutzers ausgeführt.
9 -$('.box').css('color', 'red');
Wenn möglich, fügen class
Sie einem Element immer ein hinzu, wenn Sie ein spezielles Styling benötigen. Manchmal wird das Styling jedoch dynamisch bestimmt, in diesem Fall muss es als Attribut eingefügt werden.
Modernes JavaScript
[].forEach.call( document.querySelectorAll('.box'), function(el) { el.style.color = 'rot'; // oder eine Klasse hinzufügen });
Wiederum verwenden wir die [].forEach.call()
Technik, um alle Elemente mit einer Klasse von zu filtern und sie über das Objekt box
rot zu machen .style
Vermächtnis
var box = document.getElementsByClassName('box'), // siehe Beispiel Nr. 10 unten für eine Cross-Browser-Lösung i = box.length; while ( i-- > 0 && (box[i].style.color = 'red') );
Diesmal werden wir mit der while
Schleife etwas knifflig. Ja, es ist ein bisschen bissig, nicht wahr? Im Wesentlichen imitieren wir:
var i = 0, len; for ( len = box.length; i < len; i++ ) { box[i].style.color = 'rot'; }
Da wir jedoch nur eine einzige Aktion ausführen müssen, können wir einige Zeilen einsparen. Beachten Sie, dass die Lesbarkeit weitaus wichtiger ist als das Speichern von zwei Zeilen - daher meine "snarky" Referenz. Trotzdem macht es immer wieder Spaß zu sehen, wie komprimiert man seine Loops machen kann. Wir sind Entwickler; Wir machen solche Sachen zum Spaß! Bleiben Sie trotzdem bei der for
Statement-Version.
10 -$()
Unsere Absicht ist es natürlich nicht, die gesamte jQuery-API zu replizieren. In der Regel wird bei Nicht-jQuery-Projekten die $
or - $$
Funktion als Abkürzung zum Abrufen eines oder mehrerer Elemente aus dem DOM verwendet.
Modernes JavaScript
var $ = funktion(el) { return document.querySelectorAll(el); }; // Verwendung = $('.box');
Beachten Sie, dass dies $
einfach ein Ein-Zeichen-Zeiger auf ist document.querySelector
. Es spart Zeit!
Vermächtnis
if (!document.getElementsByClassName) { document.getElementsByClassName = Funktion (cl, Tag) { var els, Übereinstimmungen = [], i = 0, len, regex = new RegExp('(?:\\s|^)' + cl + '(?:\\s|$)'); // Wenn kein Tag-Name angegeben ist, // Wir müssen JEDES Element aus dem DOM holen els = document.getElementsByTagName(tag || "*"); if ( !els[0] ) gebe false zurück; for ( len = els.länge; i < len; i++ ) { if ( els[i].className.match(regex) ) { matchs.push( els[i]); } } Rückspiele; // ein Array von Elementen, die den gewünschten Klassennamen haben }; } // Sehr einfache Implementierung. Wir suchen nur nach einer ID, Klasse oder einem Tag-Namen. // Akzeptiert keine CSS-Selektoren in Pre-querySelector-Browsern. var $ = Funktion (el, Tag) { var firstChar = el.charAt(0); if ( document.querySelectorAll ) return document.querySelectorAll(el); switch ( firstChar ) { Fall "#": return document.getElementById( el.slice(1) ); Fall ".": return document.getElementsByClassName( el.slice(1), tag ); Ursprünglich: return document.getElementsByTagName(el); } }; // Verwendungszweck $('#Container'); $('.box'); // jedes Element mit einer Box-Klasse $('.box', 'div'); // suche nach divs mit einer box-Klasse $('p'); // Alle p-Elemente erhalten
Leider ist die Legacy-Methode nicht ganz so minimal. Ehrlich gesagt sollten Sie an dieser Stelle eine Bibliothek verwenden. jQuery ist hochgradig für die Arbeit mit dem DOM optimiert, weshalb es so beliebt ist! Das obige Beispiel wird sicherlich funktionieren, unterstützt jedoch keine komplexen CSS-Selektoren in älteren Browsern; diese Aufgabe ist nur ein bisschen komplizierter!
Zusammenfassung
Es ist mir wichtig anzumerken, dass ich Sie nicht ermutige, jQuery aufzugeben. Ich benutze es in fast allen meinen Projekten. Seien Sie jedoch nicht immer bereit, Abstraktionen anzunehmen, ohne sich ein wenig Zeit zu nehmen, um den zugrunde liegenden Code zu recherchieren.
Ich möchte, dass dieser Eintrag als eine Art lebendiges Dokument dient. Wenn Sie eigene (oder Verbesserungen/Klarstellungen für meine Beispiele) haben, hinterlassen Sie unten einen Kommentar, und ich werde diesen Beitrag sporadisch mit neuen Elementen aktualisieren. Bookmarken Sie diese Seite jetzt! Abschließend möchte ich noch einen Hut auf diese Reihe von Beispielen richten , die als Anstoß für diesen Beitrag dienten.