Eine Einführung in die minimalistische JavaScript-Bibliothek Zepto

Zepto: jQuery auf Diät
Keine Kommentare

Angesichts der immensen Verbreitung der von John Resig entwickelten jQuery-Bibliothek gibt es mittlerweile ernsthafte Diskussionen, ob angehende Webentwickler lieber JavaScript oder jQuery lernen sollen. Dass das eine eine Untermenge des anderen darstellt, wird geflissentlich ignoriert. Aber was ist eigentlich mit Zepto? Manch einer mag die minimalistische JavaScript-Bibliothek mit jQuery-inspirierter Syntax schon vergessen haben. Warum sich ein Blick auf den Evergreen aber durchaus lohnt, erklärt dieser Artikel.

Abseits der für klassische Informatiker immens lustigen Debatten um jQuery und JavaScript muss allerdings festgehalten werden, dass jQuery alles andere als klein ist. In Zeiten von Content Delivery Networks mag dies nicht von besonderer Relevanz sein: Wer eine weit verbreitete Bibliothek von einem beliebten CDN einbindet, kann sich darauf verlassen, dass eine andere Website dafür gesorgt hat, dass die Datei bereits im Browsercache des Nutzers ist. In der Praxis gibt es allerdings immer wieder Situationen, wo es auf die maximale Performance ankommt. Ein Beispiel dafür wären JavaScript-basierte Prozessrechner, bei denen der zur Verfügung stehende Codespeicher nicht uneingeschränkt ist und es ob der schwachbrüstigen CPU auf jedes Kilobyte Code ankommt (Stichwort Startzeit). Zudem gibt es immer wieder Szenarien, in denen Content Delivery Networks nicht erlaubt sind oder in denen man als Entwickler Browser unterstützen muss, die von jQuery im Laufe der Zeit nicht mehr abgedeckt werden.

In diesem Moment schlägt die Stunde einer als Zepto bezeichneten Bibliothek (Kasten: „Des Handcomputerprogrammieres Liebling“). Das Projekt, im Jahr 2010 von Thomas Fuchs erdacht, ist ein Evergreen der JavaScript-Welt und zeigt sich – im Großen und Ganzen – mit jQuery kompatibel. Vor allem aber kommt das Produkt je nach Konfiguration mit 5 oder 10 KB kompiliertem Code aus.

Dieser Artikel bietet eine kurze Vorstellung der Bibliothek. Und dank des sehr kompakten Aufbaus haben wir hier sogar eine realistische Möglichkeit, das Produkt als Ganzes abzudecken.

Des Handcomputerprogrammierers Liebling

Thomas Fuchs hatte Zepto ursprünglich als abgespeckte Alternative für die Arbeit mit PhoneGap vorgesehen. Aus diesem Umstand folgt eine sehr interessante Kompatibilitätsliste. Neben den Klassikern unterstützt die Bibliothek im Großen und Ganzen nämlich auch einige seltenere Betriebssysteme. Einige besonders interessante Kandidaten sind beispielsweise Palms WebOS, ältere Versionen von Android, BlackBerry 10 und sogar alte Versionen von Safari für iOS.

Das Core-Modul von Zepto kommt minifiziert auf nur fünf Kilobyte. Es gibt immer wieder Szenarien, in denen man für die im Artikel weiter unten besprochenen Erweiterungsmodule keinen Bedarf hat und somit wirklich mit einer Dateigröße von fünf Kilobyte auskommen kann.

Eine Frage der Modularisierung

Als der Autor dieser Zeilen vor vielen Jahren an einer drittklassigen österreichischen technischen Hochschule einen Analogrechner aus dem Hause Telefunken zerlegen musste, bewunderte er den stark modularen Aufbau des in der Zerstörung befindlichen Rechenbiests. Es handelte sich um ein System, das wirklich in seine Einzelteile zerlegbar war. Sowohl bei der Reparatur als auch beim Verkauf hilfreich, konnte Telefunken auf diese Weise nicht benötigte Teile weglassen, um das Gesamtsystem preiswerter anbieten zu können.

Im Hause Zepto setzt man auf ein ähnliches Konzept. Die Bibliothek besteht aus einem guten Dutzend Modulen, die in Tabelle 1 kurz zusammengefasst sind.

Modulname Kurzbeschreibung In Standard-distribution
zepto Kernmodul ja
event Erweiterungen für eventgetriebene Programmierung ja
ajax XMLHttpRequest ja
form Methoden zur Serialisierung von Formularen ja
ie Unterstützung für Internet Explorer 10 ja
detect Erkennung von Browser und Hostbetriebssystem nein
fx „Animate()“-Methode nein
fx_methods Vordefinierte Beispielanimationen für Animate nein
assets Bessere Speicherverwaltung für iOS; experimentell nein
data „Data()“-Methode nein
deferred Möglichkeit zur Nutzung von Promises nein
callbacks Erweitert „$.Callbacks“ um die Möglichkeit, im Deferred-Betrieb zu arbeiten nein
selector Emuliert ein Subset von jQuerys CSS-Selektoren nein
touch Touchscreen-Basisbibliothek nein
gesture Gestenerkennung für Pinch-to-Zoom nein
stack Methodenverkettung nein
ios3 Unter iOS 3 nicht implementierte Hilfsfunktionen nein

Tabelle 1: Die Module von Zepto

An einer eigenen Version von Zepto interessierte Entwickler erreichen dieses hehre Ziel auf zwei Arten: Erstens kann der gesamte Quellcode heruntergeladen werden, um daraufhin unter Nutzung von Node-basierten Werkzeugen eine eigene Version zu kompilieren. Alternativ dazu bietet sich der zepto builder an, der nach dem Öffnen in einem beliebigen Webbrowser das in Abbildung 1 gezeigte Benutzerinterface auf den Bildschirm bringt.

Abb. 1. Dank des zepto builders müssen Entwickler nicht mit der Node-Kommandozeile kämpfen

Abb. 1. Dank des zepto builders müssen Entwickler nicht mit der Node-Kommandozeile kämpfen

Im Interesse der Einfachheit wollen wir an dieser Stelle trotzdem mit der Standarddistribution arbeiten, die vom Builder mit Voreinstellungen ausgeliefert wird oder alternativ dazu auch direkt auf der Projektwebseite heruntergeladen werden kann.

Für die folgenden Schritte wollen wir die minifizierte Version verwenden. Die Datei lautet zum Zeitpunkt der Drucklegung zepto.min.js und wartet auf neue Eigentümer. Laden Sie sie in einen bequem zugänglichen Platz am Dateisystem herunter, und erzeugen Sie im nächsten Schritt einen Testharnisch mit dem in Listing 1 dargestellten Code.

<html>
<head>
<script src="zepto.min.js" type="text/JavaScript"></script>
</head>
<body>
<script>
Zepto(function($){
  alert('Zepto hoch!')
})
</script>
</body>
</html>

Dieses – sehr einfache – Beispiel illustriert einige interessante Elemente der Bibliothek. Erstens setzt das Produkt immer eine globale Variable namens Zepto, die auf den Bibliothekscode als Ganzes verweist. Zweitens führt das Übergeben von Funktionen an Zepto dazu, dass Referenzen in einem internen Speicher abgelegt werden, der nach dem Auftreten des DomContentLoaded-Ereignisses abgearbeitet wird.

Nach dem Eintreffen dieses Ereignisses eingeschriebene Funktionen werden vom Framework derweil sofort ausgeführt. Wer innerhalb von Zepto(function($){ eine weitere Messagebox platzieren würde, die ebenfalls in einem Zepto(function($){-Harnisch läge, würde zwei Nachrichten auf den Bildschirm holen:

<script>
Zepto(function($){
  Zepto(function($){
    alert('Innen hoch!')
  });
  alert('Zepto hoch!')
})
</script>

Dieses auf den ersten Blick seltsame Verhalten liegt daran, dass das Framework nach der Abarbeitung von F1 bereits voll initialisiert ist und deshalb die angegebene Payload sofort ausführt. Witzigerweise erscheint die „innere“ Messagebox hier sogar vor ihrer weiter außen stehenden Kollegin.

Zepto unterscheidet sich insofern von jQuery, als es das Dollarzeichen nur dann mit eigenem Code bevölkert, wenn die Variable zum Zeitpunkt des Ladens der Bibliothek frei ist. Das führt insbesondere im Zusammenspiel mit Bibliotheken zu Ärger, denn diese führen sich ebenfalls im heiß umkämpften Dollar-Namespace ein. Wer hierzu weitere Informationen begehrt, sei z. B. auf Peter Kinmonds GitHub-Page verwiesen.

Die Haupt-und Staatsaufgabe von Zepto ist sicher das Hantieren mit DOM-Objekten. Zum Ausprobieren dieses Features müssen wir den Body unseres Elements um einige Testelemente ergänzen. Als erstes Beispiel wollen wir hierbei auf eine Gruppe von <div>-Tags setzen, was zu folgenden Code führt:

<body>
<div></div><br>
<div></div><br>
<div></div><br>
<script>
. . .

Im nächsten Schritt können wir uns der Bevölkerung der leeren Elemente zuwenden. Da das DOM hierzu voll aufgebaut sein muss, wandert der Code in einen weiteren Zepto-Wrapper:

<script>
Zepto(function($){
  $('div').forEach(function(item, index, array){
    $(item).html(index);
  });	
});
</script>

An jQuery gewöhnte Entwickler bemerken an dieser Stelle einiges, was ihnen vertraut sein sollte: Das Dollarzeichen nimmt ebenfalls Stringparameter entgegen, die als Selektoren bezeichnet werden und die kompakte Interaktion mit dem DOM-Baum ermöglichen.

Wir übergeben hier den String div, um das Framework anzuweisen, ein Array von allen <div>-Tags, die sich in der Seite befinden, zurückzugeben. Im nächsten Schritt rufen wir die Zepto-spezifische Funktion forEach auf, die sich wie ein aus .NET und Co. bekannter Iterator verhält: Die an sie übergebene Payload wird auf jedes Element des Arrays angewendet.

Von Interesse ist hierbei, dass das Framework drei Parameter bereitstellt. Neben dem eigentlich aktuellen Element und einer durchlaufenden Indexvariable überliefert Zepto aus Gründen der Bequemlichkeit auch einen Verweis auf das Hauptfeld, um die Realisierung von Logik zu erleichtern.

Die eigentliche Payload findet sich im Korpus wieder. Zepto platziert hier allerdings eine kleine Falle, die unerfahrene Entwickler frustriert. Das Framework liefert in Iteratoren gewöhnliche JavaScript-Elemente zurück, die die diversen von Zepto deklarierten Funktionen und Methoden naturgemäß nicht exponieren. Aus diesem Grund müssen wir im ersten Schritt auf die Syntax $(item) zurückgreifen, um ein Zepto-Objekt aus dem eingereichten DOM-Element zu erzeugen. Dieses ist sodann mit der Zepto-eigenen Funktion html()-kompatibel. Wie dem auch sei: Laden Sie das fertige Programm in einem Browser Ihrer Wahl, um sich an einer Sequenz verschiedener Zahlen zu erfreuen.

Diverse Helferlein

Beachten Sie in diesem Zusammenhang, dass der von Zepto ausgelieferte DOM-Parser nur eine Teilmenge der in jQuery implementierten Funktionen und Parameter enthält. Eine für CSS-abhängige Entwickler besonders lästige Einschränkung ist das Fehlen der von jQuery bekannten Selektorerweiterungen auf Basis von Style Sheets. Wer die im Detail beschriebenen Features in seinem Programm unbedingt einsetzen muss, kann auf ein als Selector bezeichnetes Modul zurückgreifen. Beachten Sie dabei allerdings, dass dieser Teil des Produkts als experimentell bezeichnet wird und im Mobilbereich traditionell eher schlecht als recht funktioniert.

Neben dem DOM-Parser bietet das Kernmodul von Zepto auch diverse andere Hilfsfunktionen an. Immer populär sind beispielsweise die isX-Methoden, mit denen Sie überprüfen können, ob ein bestimmtes Element von einem bestimmten Typ ist:

$.isArray
$.isFunction
$.isNumeric
$.isPlainObject
$.isWindow

Aufgrund der Einfachheit dieser Funktionen wollen wir hier kein Beispiel realisieren. Viel interessanter ist es, die im core-Modul enthaltenen DOM-Manipulationsfunktionen weiter zu analysieren. So gibt es mit scrollLeft und scrollTop eine Gruppe von Methoden, die das Ermitteln und das programmatische Beeinflussen der Scrollposition am Bildschirm erlauben.

Ein weiteres lustiges Helferlein hört auf den Namen Grep: $.grep(items, function(item){ … }) ⇒ array. Unix-erfahrene Entwickler können ahnen, was hier folgt: Die Methode nimmt neben einem Feld eine Callback-Funktion entgegen, die für jedes Element des Arrays aufgerufen wird. Das resultierende Array ist sodann ein Feld jener Elemente, bei denen das Callback true lieferte – ein nettes Werkzeug zur Dezimierung von Feldern anhand komplexer Kriterien.

Ted lässt grüßen

Ted Faisons Ausführungen zur eventorientierten Programmierung dürften mittlerweile ein Klassiker sein. Auch gute zehn Jahre nach seinem erstmaligen Erscheinen ist das entsprechende Buch weiter im Handel. Die Zepto-Standarddistribution wird ebenfalls mit einer Eventverwaltung ausgeliefert, die Entwicklern das Einbinden von anderen Frameworks wie Radio.js und Co. erspart.

Auch wir wollen hier ein kleines eventorientiertes Programm realisieren. Erzeugen Sie hierzu eine neue Version des weiter oben abgedruckten Testharnischs, der nun allerdings mit einem Button ausgestattet werden muss. Da die Deklaration von Knöpfen nicht zu den großen Mysterien der Systemtechnik gehört, drucken wir den hierzu notwendigen Code an dieser Stelle nicht ab.

Stattdessen wollen wir einen Blick auf Eventquellen werfen. Zepto unterstützt sowohl im DOM befindliche als auch vom Entwickler selbst angelegte Ereignisse. Wir wollen hier mit einem hausgemachten Event beginnen. Es wird unter Nutzung der Methode $.Event beim Framework angemeldet:

Interessant ist in diesem Zusammenhang eigentlich nur, dass das Auslösen des Ereignisses ebenfalls unter Nutzung eines DOM-Objekts erfolgen muss. Öffnen Sie die Datei sodann in einem Browser Ihrer Wahl und klicken Sie den Knopf an. Das Message-Box-Fenster erscheint wie erwartet am Bildschirm.

Eines der interessantesten Features von eventgetriebenen Systemen ist die Möglichkeit, Ereignisse in bestimmten „Kanälen“ weiterzuleiten. Hierzu wollen wir unseren kleinen Testharnisch um einen weiteren Event Handler erweitern:

$("#aButton").on('sus:event', function(e){
  alert("Ereignis ausgelöst!");
})
$(document.body).on('sus:event', function(e){
  alert("Ereignis ausgelöst!");
})

Aus technischer Sicht finden hier sich nur wenige Unterschiede. Wir schreiben dem Ereignis nun sowohl auf Ebene des Buttons als auch auf Ebene des Dokumentenkörpers einen Ereignis-Handler ein. Beide zeigen je eine Messagebox an, weshalb das Zählen der angezeigten Fenster Informationen über die Programmausführung liefert. Bei der Auslösung mit dem weiter oben abgedruckten Event Handler erscheinen zwei Messageboxen am Bildschirm. Dieses Verhalten ist amüsanterweise vom Wert der bubble-Variable unabhängig. Ein interessantes Verhalten zeigt sich beim Anpassen des Klick-Handlers:

$("#aButton").on('click', function(e){
  $(document.body).trigger('sus:event',[])
})

Wer das Ereignis direkt in Document.Body auslöst, stellt fest, dass nur eine Message am Bildschirm erscheint. Das liegt daran, dass Zepto Ereignisse, wenn überhaupt, prinzipiell nur nach oben überträgt. Ein attraktiver Workaround für dieses Problem ist die Nutzung der Methode triggerHandler:

$("#aButton").on('click', function(e){
  $("#aButton").triggerHandler('sus:event',[])
})

Ein mit triggerHandler ausgelöstes Ereignis wird von Zepto auf das DOM-Element beschränkt, in dem die Methode aufgerufen wurde. In unserem Fall bedeutet das, dass nur jene Event Handler zum Einsatz kommen, die auf Ebene des Buttons angelegt wurden.

Und jetzt mobil!

Als nächste Aufgabe wollen wir uns dem Handling von Touchscreen-Ereignissen zuwenden. Auch wenn Zepto ursprünglich als Mobile-Framework vorgesehen war, wird dieses Modul von Haus aus nicht mit dem Gesamtframework ausgeliefert und muss vor der erstmaligen Nutzung eingebunden werden.

Wer sich die weiter oben besprochene Arbeit mit dem Customizing ersparen möchte, kann auch die bereitstehende Datei touch.js herunterladen und nach folgendem Schema „zusätzlich“ zum normalen Framework in den Testharrnisch einbinden:

<head>
<script src="zepto.min.js" . . .
<script src="touch.js" type="text/JavaScript"></script>
</head>

Zum Test der diversen Elemente müssen wir im Body eine Struktur aus einigen Elementen anlegen: aus Gründen der Bequemlichkeit beschränken wir uns auf zwei LI-Tags:

<body>
<ul id=items>
  <li class=feld>List item 1: <span>Element A</span></li>
  <li class=feld>List item 2: <span>Element B</span></li>
</ul>

Auch wenn dieser Artikel nicht auf Touchscreen-Usability als Ganzes eingehen kann, sei explizit darauf hingewiesen, dass Steuerelemente in Handcomputerapplikationen so groß wie möglich angelegt werden sollen. Dies lässt sich am einfachsten unter Nutzung von etwas CSS bewerkstelligen:

<body>
<style>.feld
{
  height: 200px;
  width: 600px;
  background-color: powderblue;
  margin: 30px 30px 30px 30px;
}
</style>

Zur Bereitstellung der Inhalte fürs Smartphone bietet sich das Anlegen eines lokalen HTTP-Servers an. Unter Unix arbeitende Entwickler können hier nach dem Schema in Listing 2 auf ein kleines Python-Programm setzen – unter Python 3 müssen sie statt SimpleHTTPServer ein anderes Beispiel laden.

tamhan@TAMHAN14:~/SUSZepto$ python -m SimpleHTTPServer 8080
Serving HTTP on 0.0.0.0 port 8080 ...
Der Korpus des Programms ist – analog zu jQuery – alles andere als komplex:
<script>
Zepto(function($){
  $('#items li').longTap(function(){
    $('.feld').css('background-color', '#369')
  })
});
</script>

Laden Sie das Programm sodann auf einem Smartphone Ihrer Wahl und führen Sie einen Long Tap aus. Die Hintergrundfarbe der Elemente verändert sich wie in Abbildung 2 gezeigt.

Abb. 2: Aus hell- mach dunkelblau, hier unter Chrome for Android

Abb. 2: Aus hell- mach dunkelblau, hier unter Chrome for Android

Neben dem longTap-Ereignis können Entwickler auch einzelne Taps abrufen. Hierzu gibt es drei Ereignisse: tap nimmt alle Tap-Ereignisse an, während singleTap und doubleTap bestimmte Tap-Arten anzielen. Swipes lassen sich unter Nutzung der Methoden swipe, swipeLeft, swipeRight, swipeUp und swipeDown handhaben. Hier ist allerdings Testing erforderlich, weil sie nicht unter allen Browsern gleichermaßen funktionieren.

Formular in schnell

Zepto bringt eine vollwertige Ajax-Implementierung mit. Da das Hantieren mit AccessControl und Co. in Arbeit ausartet, wollen wir hier nur die Serialisierung vorstellen. Hierzu wird das Form-Modul verwendet, das gemäß Tabelle 1 von Haus aus in der Standarddistribution enthalten ist. Als Testharnisch soll folgende DOM-Struktur dienen:

<form id="myID">
<input type="text" name="firstname"><br>
<input type="radio" name="active"> <br>
<input type="submit" value="Submit">
</form>

Das Einsammeln der Ergebnisse eines Formulars kann sowohl in Form eines Arrays als auch in einem direkt übertragbaren String erfolgen. Zepto bietet eine eigene Methode an, die das Einschreiben von Event Handlern in das Submit-Ereignis ermöglicht. Aus Platzgründen realisieren wir hier keine komplette Ausgabe. Abbildung 3 zeigt, wie die beiden Elemente im Debugger aussehen.

Abb. 3: Zepto serialisiert Formulardaten automatisch

Abb. 3: Zepto serialisiert Formulardaten automatisch

Fazit

Bei allen Überlegungen darf nicht außer Acht gelassen werden, dass sich die Entwicklung von Zepto im Laufe der letzten Monate massiv verlangsamt hat. Während jQuery nach wie vor jeden Tag einige Updates ausfasst, herrscht im Hause Zepto mittlerweile fast komplett Ruhe.

Für Entwickler ist das allerdings nicht unbedingt nachteilig, die Bibliothek tut ja im Großen und Ganzen, was sie soll. Dass man im Fall eines Bugs selbst Hand anlegen muss, ist ein beachtenswerter Nachteil. Zudem gilt, dass die Kompatibilität mit Drittanbieterbibliotheken immer ein „Maybe“ ist. Zerstört ein Update die Applikation, so ist der Anbieter einer auf jQuery basierten Bibliothek normalerweise nur wenig an ihrem Bug Report interessiert.

PHP Magazin

Entwickler MagazinDieser Artikel ist im PHP Magazin erschienen. Das PHP Magazin deckt ein breites Spektrum an Themen ab, die für die erfolgreiche Webentwicklung unerlässlich sind.

Natürlich können Sie das PHP Magazin über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist das Entwickler Magazin ferner im Abonnement oder als Einzelheft erhältlich.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu:
X
- Gib Deinen Standort ein -
- or -