Fliegengewicht

Javascript Bibliothek jQuery

Jörn Zaefferer

JavaScript zu beherrschen ist für einen erfahrenen Java-Entwickler keine große Herausforderung. Inkonsistenzen in den DOM-APIs der Browser, Bugs im Eventsystem oder Darstellungsfehler in der CSS-Rendering-Engine machen es hingegen sehr schwer, browserübergreifend JavaScript zu entwickeln. Wie jQuery diese Probleme löst, soll in diesem Artikel vorgestellt werden.

John Resig, mittlerweile bei der Mozilla Foundation tätig, hat im Sommer 2005 die Idee veröffentlicht, aus der jQuery entstanden ist. Im Januar 2006 hat er die erste Version veröffentlicht, ein halbes Jahr später Release 1.0. Die Fortschritte, die in dieser Zeit gemacht wurden, sind neben der Arbeit des jQuery-Teams vor allem der jQuery-Community zu verdanken.

jQuery selbst besteht aus einem Modul zur Selektion und Manipulation von Elementen in einem HTML- oder XML-Dokument, repräsentiert durch das Document Object Model (DOM), sowie Modulen zur Behandlung von Events, Effekten (FX) und AJAX.

JavaScript jQuery aus OOP-Sicht

Aus der Perspektive der klassenbasierten objektorientierten Programmierung besteht jQuery aus einer einzelnen Klasse mit vielen Methoden und einigen wenigen statischen Methoden. Instanziiert wird ein jQuery-Objekt durch Aufruf einer Factory-Methode. Dieses Objekt kapselt eine Liste von DOM-Elementen. Aufrufe von Methoden geben eine neue jQuery-Instanz zurück, wenn sie das jQuery-Objekt selbst verändern, z.B. durch Hinzufügen oder Entfernen von Elementen aus der Liste. Diese neue Instanz enthält eine Referenz auf die vorherige Instanz. Methoden-Aufrufe, die lediglich die gekapselten Elemente ändern, geben dieselbe Instanz zurück. Methoden, die Werte aus den DOM-Elementen lesen oder berechnen, geben einen dem entsprechenden Wert zurück, z.B. einen String für den eingegebenen Wert eines input-Elements oder eine Zahl für den Transparenz-Wert (opacity) eines divs. Die meisten jQuery-Methoden werden genau wie Plug-in-Methoden dem prototype-Objekt der jQuery-Funktion hinzugefügt. Dadurch lässt sich die jQuery-Klasse auch zur Laufzeit noch beliebig erweitern, ohne Konstrukte wie Reflection oder Bytecode-Manipulation. Auf diesem Kern aufbauend gibt es eine Vielzahl an Plug-ins, die die Basisfunktionalität um facettenreiche Aspekte erweitern. Die meisten Plug-ins sind wie jQuery selbst unter MIT und GPLlizensiert. Daher steht einem Einsatz sowohl in kommerziellen als auch in Open-Source-Projekten nichts im Wege.

Auf diesem Kern aufbauend gibt es eine Vielzahl an Plug-ins, die die Basisfunktionalität um facettenreiche Aspekte erweitern. Die meisten Plug-ins sind wie jQuery selbst unter MIT und GPL lizensiert. Daher steht einem Einsatz sowohl in kommerziellen als auch in Open-Source-Projekten nichts im Wege.

Hello, World

Der Einsatz von jQuery kann methodisch in zwei Aspekte aufgeteilt werden: Etwas selektieren, und damit etwas tun. Zum Selektieren werden CSS 1-3 Selektoren und teilweise XPath unterstützt. Das macht den Einstieg mit entsprechenden Vorkenntnissen sehr leicht. Das „etwas tun“ fängt beim Ändern von Attributen oder Inhalten eines oder mehrerer Elemente an, und geht über Animationen bis zum Transformieren in komplette Widgets. Schauen wir uns zuerst das triviale, aber sehr hilfreiche „Hello, World“ in jQuery an:

<script src="jquery.js" type="text/javascript">
<script type="text/javascript">
$(document).ready( function() {
$(".headline" ).html("<h1>Hello, World!</h1>")
});
</script>

Nach dem Einbinden von jQuery muss sichergestellt werden, dass unser Code erst ausgeführt wird, wenn alle zu selektierenden Elemente auch geladen sind. Der window.onload-Event ist dafür nicht optimal, da er erst ausgeführt wird, wenn z.B. alle Bilder komplett geladen sind. Der DOM-ready-Event, den uns jQuery dafür zur Verfügung stellt, erlaubt uns die Ausführung unserer Scripte zum frühest möglichen Zeitpunkt.

In der nächsten Zeile selektieren wir alle Elemente mit der Klasse „headline“ und verwenden dazu einen CSS-Selektor. Der Aufruf von (ein Alias für jQuery()) arbeitet dabei als Factory-Methode: Wir bekommen ein neues Objekt zurück, das alle selektierten Elemente kapselt, aber auch leer sein kann. Die html()-Methode benutzen wir, um den HTML-Inhalt der selektierten Elemente zu ändern. Dabei spielt es keine Rolle, ob wir keins, eins oder beliebig viele Element selektiert haben, unser manipulierender Aufruf wirkt automatisch auf alle. jQuery nimmt uns die Arbeit ab, selbst Schleifen zu schreiben.

[ header = Seite 2: Hör mal wer da… ]

Hör mal wer da…

Viele Anforderungen bei der JavaScript-Entwicklung drehen sich um die Verbesserung des Userinterface. Im Folgenden betrachten wir das Beispiel von Tooltips, um jQuery näher kennen zu lernen. Schauen wir erst einmal, wie Tooltips normalerweise im Browser aussehen:

Abb. 1: Tooltip im Firefox 2.0

Solange uns konkrete Vorgaben fehlen, können wir uns einfach fertige Implementierungen anschauen, z.B. sind die Tooltips in Office 2007 recht schick:

Abb. 2: Tooltip in Microsoft Office 2007

Auf den Verlauf im Hintergrund verzichten wir zunächst, daher können wir den Tooltip gut mit ein wenig CSS gestalten (Listing 1 und Abb. 3).

Abb. 3: Der mit CSS gestaltete Tooltip, hier noch statisch erzeugt

Listing 1
--------------------------------------------------------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http: //www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<style type="text/css">
#tooltip {
position: absolute;
z-index: 3000;
top: 40px;
left: 80px;
border: 1px solid black;
background-color: #dde7f5;
padding: 5px;
font-size: .7em;
font-family: verdana;
}
#tooltip h3, #tooltip p {
margin: 0;
}
#tooltip h3 {
font-size: 1.1em;
margin-bottom: .5em;
}
</style>

<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready() {
//Hier kommt unser Code hin.
});
</script>

</head>
<body>
<a title="Alles Lesenswerte anzeigen" href="lesenswertes.html">Lesenswertes</a>
<br/>
<a title="Alles Langweilige anzeigen" href="langweilig.html">Langweiliges</a>
<div id="tooltip">
<h3>Lesenswertes</h3>
<p>Alles Lesenswerte anzeigen</p>
</div>
</body>
</html>
/Listing 1

Im nächsten Schritt müssen wir uns überlegen, wann und wie unser Tooltip angezeigt werden soll:

  • Der Tooltip soll für alle Links mit einem title-Attribut angezeigt werden.
  • Beim Überfahren mit der Maus angezeigt, beim Verlassen versteckt werden.
  • Als Headline soll der Linktext, als Beschreibung der Inhalt des title-Attributs angezeigt werden.

Alle folgenden Codebeispiele fügen wir in den entsprechend kommentierten Scriptblock ein (Listing 1). Als erstes selektieren wir alle Links mit einem title-Attribut. Dazu verwenden wir einen XPath-Ausdruck für die hat-ein-title-Attribut-Bedingung:

$("a[@title]")

Die üblichen Events für unseren Zweck wären mouseover und mouseout, jQuery bietet uns zusätzlich den hover-Event. Diesen nutzen wir, indem wir die hover()-Methode unseres jQuery-Objekts aufrufen und ihr zwei Callback-Funktionen übergeben:

function over() {
console.log("over");
}
function out() {
console.log("out");
}
$("a[@title]").hover( over, out );

Um erst einmal testen zu können, ob unser Code soweit stimmt, benutzen wir das Logging, das uns die Firefox-Erweiterung Firebug bietet. Wenn wir jetzt das Beispiel testen und im Browser den Link überfahren, bekommen wir auf der Konsole von Firebug entsprechend over und out ausgegeben. Das ist wesentlich effektiver als das umständliche alert()-Logging.

Im nächsten Schritt ersetzen wir das Logging durch Code zum Anzeigen und Verstecken des Tooltip-Elements:

var tooltip = $("#tooltip").hide();
function over() {
tooltip.show();
}
function out() {
tooltip.hide();
}
$("a[@title]").hover( over, out );

In der ersten Zeile selektieren wir mit dem CSS-ID-Selektor das Tooltip-Element, verstecken es und weisen es einer Variablen zu. Auf diese greifen wir von unseren Callbacks aus zurück.

Jetzt müssen wir noch den Tooltip richtig positionieren und seinen Inhalt anpassen, denn derzeit zeigt er immer dasselbe an derselben Stelle an. Außerdem sehen wir immer noch den Standard-Tooltip des Browsers. Zur Positionierung verwenden wir die Eigenschaften pageX und pageY des Event-Objekts und die css()-Methode von jQuery. Mit den Methoden html()text() und attr() holen und setzen wir Attribute, HTML- und Textinhalte. Mit attr() merken wir uns auch das title-Attribut des aktuellen Elements, entfernen es und stellen es wieder her (Listing 2).

Listing 2
-------------------------------------------------------------------------
<script type="text/javascript" src="jquery.js""></script>
<script type="text/javascript">
$(document).ready(function() {
var tooltip = $("#tooltip").hide();
var title;
function over(event) {
var current = $(this);
title = current.attr("title");
current.attr("title", "");
tooltip.find("h3").html( current.text() );
tooltip.find("p").html( title );
tooltip.css({
left: event.pageX + 15,
top: event.pageY + 15
}).show();
}
function out() {
$(this).attr("title", title);
tooltip.hide();
}
$("a[@title]").hover( over, out );
});
</script>

Da alle Variablen, die wir definieren, innerhalb der Funktion stehen, die wir an die ready()-Methode übergeben, hinterlassen wir hier keine einzige globale Variable oder Funktion. Gut zu wissen ist auch, dass innerhalb von Event-Callbacks this immer das Element referenziert, das den Event behandelt. Durch jQuery(this) können wir alle jQuery-Methoden auf dieses Element anwenden.

Da diese Tooltip-Implementierung noch viele Wünsche offen lässt, verweise ich auf mein mittlerweile ausgereiftes Tooltip-Plug-in. Neben diesem gibt es mittlerweile eine große Auswahl an Plug-ins für jQuery. Eines davon, Autocomplete, wollen wir uns im Folgenden genauer anschauen.

[ header = Seite 3: Souffleur fürs Web ]

Souffleur fürs Web

In Excel gibt es schon länger die Funktion, die bei Eingabe eines Werts in eine Zelle Werte vorschlägt, die in derselben Spalte bereits verwendet wurden (Abb. 4). In E-Mail-Clients bekommt man bei Eingabe der Zieladresse eine Auswahl aus dem eigenen Adressbuch vorgeschlagen (Abb. 5).

Abb. 4: Autocomplete in Excel

Abb. 5: Autocomplete in Thunderbird

Im Web findet man ebenfalls zahlreiche Beispiel: Bei buch.de bekommt man bereits bei Eingabe eines Suchbegriffs Ergebnisse vorgeschlagen (Abb. 6). Google Mail bietet ebenfalls die Vervollständigung von Empfängern aus dem Adressbuch, hier allerdings mit Eingabe von mehreren Adressen in ein einzelnes Feld (Abb. 7).

Abb. 6: Autocomplete auf buch.de

Abb. 7: Autocomplete in Google Mail

Bei der Suche von buch.de liegt den Vorschlägen eine große Datenmenge zugrunde, bei Google Mail hingegen wird lediglich das Adressbuch des Benutzers herangezogen, das im Schnitt aus ein paar Dutzend Einträgen besteht. Anhand dieser Datenmenge muss entschieden werden, ob die Daten lokal vorgehalten werden können oder per AJAX nachgeladen werden müssen. In letzterem Fall kann ein geschicktes Caching die Anzahl der Requests deutlich verringern.

Das Autocomplete Plug-in kann diese Anforderungen bereits sehr gut abdecken. Im einfachsten Fall muss lediglich entschieden werden, ob mit lokalen oder entfernten Daten gearbeitet werden soll. In unserem ersten Beispiel testen wir lokale Daten (Listing 3).

Listing 3
---------------------------------------------------------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http: //www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>

<link rel="stylesheet" type="text/css" href="jquery.autocomplete.css" />

<script type="text/javascript" src="jquery.js"></script>
<script type='text/javascript' src='jquery.bgiframe.min.js'></script>
<script type='text/javascript' src='jquery.below.js'></script>
<script type="text/javascript" src="jquery.autocomplete.js""></script>
<script type="text/javascript">
$(document).ready(function() {
$("#wetter").autocomplete([
"Sonnig",
"Bewölkt",
"Regnerisch",
"Stürmisch",
"Schneesturm"
]);
});
</script>

</head>
<body>
<label for="wetter">Bevorzugte Wetterlage</label>
<input id="wetter" name="wetter" />
</body>
</html>

Das Autocomplete-Plug-in benötigt neben jQuery selbst noch zwei weitere Plug-ins, below und bgiframe. Nach dem Einbinden selektieren wir unser Eingabefeld anhand seiner ID und übergeben der Autocomplete-Methode ein Array mit Daten. Fängt der Benutzer jetzt an zu tippen, bekommt er passende Vorschläge präsentiert (Abb. 8).

Das Arbeiten mit entfernten Daten ist in unserem Code noch einfacher:

$("#ort").autocomplete("url-zum-backend");

Hier ist die Serverseite mehr gefordert. Sobald der Benutzer etwas eingibt, wird per AJAX ein Request gesendet, dessen Parameter „q“ den eingegebenen Wert enthält. Serverseitig muss nun eine Liste möglicher Werte zusammengestellt werden, in der Regel durch ein SQL-Query mit einer where-like-Bedingung. Per Default erwartet das Plug-in als Antwort einen Wert pro Zeile, wie fast alles andere kann auch dies angepasst werden. Detaillierte Beispiele befinden sich im Download des Plug-ins. Auf der Heft-CD ist eine Java-Webanwendung, in der das Plug-in auf ein eigenes Servlet zugreift und somit auch in einer Portletumgebung funktioniert.

Fazit

Durch Nutzen des kompakten jQuery-Kerns und bedarfsabhängiger Erweiterung in Form von Plug-ins lassen sich Webseiten und Webanwendungen leicht um vielfältige Aspekte erweitern. Vor allem für Webseiten ist die geringe Dateigröße von Vorteil, denn jQuery selbst ist komprimiert gerade mal 20kb groß.
Aufgrund der Fähigkeit von jQuery, mit geringem Aufwand beliebige Elemente im Dokument zu selektieren, lassen sich auch bestehende Anwendungen problemlos mit jQuery nachrüsten. Mehr zu lesen über jQuery gibt es bald in Form von „Learning jQuery : Better Interaction Design and Web Development with Simple JavaScript Techniques“.

Geschrieben von
Jörn Zaefferer
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.