Im alten zerbit.de-Web hatte ich den Zugriff auf ältere Beiträge über die Archiv-Seite zusammengefasst und vereinfacht.
Als die Filter- und Sortierungsfunktionen fertig waren, kam ich auf die Idee per Javascript eine Vorschau zu
implementieren, die es ermöglicht einen Blick auf den Beitrag zu werfen,
ohne die Seite neu laden zu müssen.
Um nun nicht alle Beiträge von vorneherein in unsichtbaren DIV's vorhalten zu müssen,
was die Ladezeit der Seite extrem in den Keller gezogen hätte, habe ich die
zeitgemäße AJAX-Technik
angewandt, soll heißen: der Text eines Beitrags wird auf Anfrage, also auf
den Klick eines Benutzers hin, vom Server geladen und angezeigt.
Der dafür notwendige Javascript-Code war nach Fertigstellung fast 90
Zeilen lang! Ein ziemlicher Brocken, nur um den Inhalt einer XML-Datei in
ein scrollbares DIV zu laden.
Nun habe ich mich vor Kurzem, im Zuge eines
Beitrags über das Anzeigemodul Thickbox,
etwas mit der Javascript-Bibliothek jQuery beschäftigt und die Frage war, in
wieviel Zeilen man das Problem wohl damit abhandeln kann. Das Ergebnis:
30 Zeilen, inkl. Kommentare und Leerzeilen zwecks Übersichtlichkeit des
Codes!
Diese doch erstaunliche Zahl, hat mich dazu bewogen, das Problem und die
beiden Lösungsansätze in diesem Artikel einmal näher darzustellen, um einen
kleinen Einblick in diese wirklich coole Bibliothek zu vermitteln.
Der HTML-Code
Ausgangspunkt war folgendes, für dieses Beispiel etwas vereinfachtes,
HTML-Konstrukt:
<ul>
<li>
<div class="item">
<div id="iteminfo" class="iteminfo">
<div class="mini">Beitragsdatum</div>
<div class="title"><a href="#">Beitragstitel</a></div>
<div class="mini">Schlagworte: ...</div>
</div>
<div id="selector" class="selector_plus">
<a href="javascript: showPreviewSelector();">
<img id="selimg" src="selector_plus.gif" height="50" width="20">
</a>
</div>
</div>
<div id="preview" class="preview">
<div id="previewbox">
<div id="previewtext" class="previewtext"> </div>
</div>
</div>
</li>
</ul>
Der Aufbau ist recht simpel: innerhalb einer Liste (UL / LI) sind zwei
übereinander liegende DIV's
definiert (item und preview), wobei das erste durch zwei weitere DIV's unterteilt sind (itemfo
und selector). In iteminfo sind die Informationen
zum Beitrag untergebracht und in selector ist eine Link-Grafik
definiert.
Das DIV preview ist nach dem Laden der Seite durch die
CSS-Anweisung display:none zunächst unsichtbar, da die Vorschau ja erst nach
Aufforderung, d.h. Klick auf die Link-Grafik geladen werden soll. (Die
komplette Beispiel-HTML-Datei inkl. CSS-Anweisungen und Scripte können weiter unten
heruntergeladen werden.)
Das Ganze sieht im Browser dann so aus:

Die Daten
Da der Beitragstext nicht in der Seite enthalten ist, muss er irgendwo
her kommen. Weil nun das X in AJAX für XML steht, habe ich hierfür auch dieses
Format verwendet. Die Struktur der XML-Datei ist denkbar einfach:
<?xml version="1.0" encoding="iso-8859-1"?>
<data>
<![CDATA[
... Beitragstext
]]>
</data>
Um das Ganze flexibel zu halten, hatte ich für das Archiv auf zerbit.de natürlich keine starre
XML-Datei im Einsatz, sondern etwas ASP-Code, um das XML-Konstrukt dynamisch
zu erzeugen. In diesem Beispiel verwende ich jedoch die Datei daten.xml.
Lösung 1 - reines Javascript
Nun zum dynamischen Teil der Seite. Aufgabe ist es, die im HTML-Code
bereits definierte Javascript-Funktion showPreviewSelector()
mit Leben zu füllen. In Abhängigkeit des aktuellen Status, soll folgendes
passieren:
Vorschau wird nicht angezeigt (aufklappen)
- Laden des Beitragstextes aus der XML-Datei in das DIV
previewtext
- Anzeigen des übergeordneten DIV's
preview
- Ändern der Link-Grafik und des Hintergrundes des DIV's
selektor
Vorschau wird angezeigt (zuklappen)
- Verbergen des DIV's
preview
- Ändern der Link-Grafik und des Hintergrundes des DIV's
selektor in den Originalzustand
Zum Laden von Daten von einem Web-Server per Javascript, wird das XMLHTTP-Objekt verwendet. Um dieses, Browser-unabhängig, korrekt zu
initialisieren,
verwende ich eine eigenständige Funktion, die das Objekt in einer globalen
Variable vorhält:
//globales XMLHTTP-Objekt
var xmlHttp = false;
// --------------------------------------------------------------
function getXMLRequester() {
var xmlHttp = false;
try {
// Mozilla und Co.
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else {
// Falls nicht unterstützt
xmlHttp = false;
}
}
catch( excNotLoadable )
{
xmlHttp = false;
}
return xmlHttp;
}
Dieser Requester wird dann in der eigentlichen Funktion
showPreviewSelector einmal aufgerufen und man kann über das globale
Objekt mit einem Web-Server kommunizieren.
Eine Eigenart des asynchronen Laden von Server-Daten ist, dass man
innerhalb des Codes die Rückmeldungen des Servers abwarten muss, bevor man
fortfahren kann. Aus diesem Grunde scheint der nachfolgende Code der
Funktion etwas zerklüftet:
function showPreviewSelector() {
//Zugriffsvariablen für die benötigten Seiten-Elemente
var eSel = document.getElementById("sel");
var eSelImg = document.getElementById("selimg");
var ePrv = document.getElementById("prv");
var ePrvTxt = document.getElementById("prvtxt");
//in Abhängigkeit des aktuellen Status...
if (eSel.className == 'selector_minus') {
//Vorschau-DIV verbergen und Selektor formatieren
ePrv.style.display = 'none';
eSel.className = 'selector_plus';
eSelImg.src="selector_plus.gif";
} else {
//event. bereits laufenden XMLHTTP-Request abbrechen
if( xmlHttp && xmlHttp.readyState ) {
xmlHttp.abort( );
xmlHttp = false;
}
//neue Instanz; Abbruch wenn fehlschlägt
if( !xmlHttp ) {
xmlHttp = getXMLRequester( );
if( !xmlHttp )
return;
}
//Daten-URL festlegen
var sURL = 'http://localhost/test/art61/data.xml';
//Daten abholen und verarbeiten...
xmlHttp.open("GET", sURL, true);
//Verarbeitung, wenn Status OK
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
//Text aus XML extrahieren
var xmlDok = xmlHttp.responseXML;
var sText = xmlDok.getElementsByTagName("data")[0].firstChild.nodeValue;
//Text in Vorschau-DIV einfügen
ePrvTxt.innerHTML = sText;
//Vorschau-DIV anzeigen und Selektor formatieren
ePrv.style.display = 'block';
eSel.className = 'selector_minus'
eSelImg.src="selector_minus.gif";
}
}
}
xmlHttp.send(null);
}
}
Die Entscheidung welcher Status gerade anliegt, wird an der anliegenden
CSS-Klasse des DIV's selector festgemacht. Es gibt hier nur die
beiden "Zustände" selector_plus (Vorsschau ist zu) und selector_minus
(Vorschau ist offen).
Wie man sieht, ist der reine Javascript-Code recht umfangreich, was vor
allem daran liegt, dass es keine eingebaute Möglichkeit gibt einfacher Daten
von einem Web-Server zu laden.
Lösung 2 - jQuery
Sooo... und nun das Ganze noch einmal. Nun aber unter Zuhilfenahme der
Javascript-Bibliothek jQuery von John
Resig. Sinn dieser Bibliothek ist es, den Web-Entwickler etwas von der
Javascript-Komplexität zu entlasten und schneller zu Ergebnissen kommen zu
lassen.
Um sie zu verwenden, muss man zunächst im HEAD der Seite einen ensprechenden Verweis
aufnehmen:
<script type="text/javascript" src="jquery.js"></script>
Einer der herausragenden Unterschiede zum puren Javascript ist der fortan
wesentlich schnellere Zugriff auf Objekte des
HTML-DOM, also der Seitenelemente,
wobei man wissen muss, dass man auf alle jQuery-Objekte über die $-Methode
zugreift, die die jQuery-Bibliothek repräsentiert. So verkürzt sich z.B. die
Javascript-Anweisung
document.getElementById("selector").className == 'selector_minus'
auf
$("#selector").attr("class") == 'selector_minus'
Und dies ist noch eines der längeren und simpleren Beispiele. Wer sich
einen Überblick über die jQuery-API und die Syntax verschaffen möchte, dem
sei u.a. Visual jQuery
empfohlen.
Aber konzentrieren wir uns auf unsere Aufgabe...
Das absolute Killer-Argument für jQuery ist seine AJAX-Funktionalität,
d.h. das sog. jQuery AJAX-Plugin, das in der aktuellen Version bereits in
der Bibliothek enthalten ist. Mit dieser Schnittstelle kann man kompletten "Overhead"
des XMLHTTP-Request getrost zu vergessen. Eine Seite von einem Web-Server zu
laden geschieht im einfachsten Fall mit einer Zeile:
$("#test").load("http://localhost/test/test.html");
Mit der Methode $.get und der Angabe einer
Callback-Funktion als Parameter, ist es möglich eine XML-Datei zunächst zu
laden und dann über eine XPath-Anweisung den Inhalt eines bestimmten
XML-Asts auszulesen. Dieses Feature ist prädestiniert für unsere Lösung:
function showPreviewSelectorJ() {
//abzurufende URL festlegen
var sURL = 'http://localhost/test/art61/data.xml';
if ($("#selector").attr("class") == 'selector_minus') {
//Vorschau-DIV verbergen und Selektor formatieren
$("#preview").slideUp("normal");
$("#selector").removeClass().addClass("selector_plus");
$("#selimg").src("selector_plus.gif");
} else {
//Selektor formatieren
$("#selector").removeClass().addClass("selector_minus");
$("#selimg").src("selector_minus.gif");
//über AJAX-Methode Daten holen
$.get(sURL, function(xml){
var text = $("data",xml).text();
//Text in Vorschau-DIV einfügen
$("#previewtext").html(text);
//Vorschau-DIV anzeigen
$("#preview").slideDown("normal");
});
}
}
Wie man sieht ist der jQuery-getriebene Javascript-Code wesentlich kürzer
und, wie ich finde, auch einfacher zu verstehen, auch wenn man sagen muss,
dass die jQuery-Bibliothek bei jedem Aufruf der Seite zusätzlich geladen
werden muss. Bei den heutigen Bandbreiten sollte dies aber kein
Hinderungsgrund sein.
Im Beispiel verstekt ist noch ein Goodie, dass mit der reinen
Javascript-Lösung so nicht realisiert wurde: das DIV preview wird nicht nur
einfach angezeigt, sondern es enfaltet sich effektvoll. Zuständig hierfür
ist die Zeile $("#preview").slideDown("normal");. Dies ist
allerdings nur ein Effekt der Bibliothek. Es gibt zig-verschiedene Arten, um
HTML-Elemente "erscheinen" zu lassen.
Das Ergebnis
Der Vollständigkeit halber noch ein Screenshot der ausgeklappten
Vorschau...

Downloads
Beispieldateien zu diesem Artikel
Weiterführende Informationen