Akkordeon Effekt mit der Yahoo! User Interface Library
Der Akkordion Effekt ist in der letzten Zeit durch die Verwendung von JavaScript Bibliotheken immer populärer geworden. In dem webthreads WM 2006 Info Mashup wurde dieser Effekt für die Darstellung der WM Stadien sowie der WM Länder genutzt.
Einige Bibliotheken bieten diesen Effekt schon von Haus aus an und mann kann ihn direkt einsetzen. Mit der Yahoo! User Interface Library (YUI) muss man sich diesen Effekt erst noch “bauen”. Im folgenden wird erläutert was zu diesem Effekt benötigt wird und wie das Ergebnis aussehen kann. Wie schon im Artikel zu dem WM Info Mashup angekündigt hier nun also das erste Tutorial.
Gliederrung:
- Live Beispiel
- Benötigte YUI Library Komponenten
- Aufbau des HTML für die Akkordion Elemente
- Akkordion JavaScript
- Über alle gegebenen Akkordion Elemente iterieren
- Jedes Akkordion Element speichern und das aktive Element finden
- Jedem Element die Akkordion Animation als Click-Event registieren
- Ressourcen
Live Beispiel
Das fertige Akkordion Beispiel sieht am Ende wie folgt aus:
Die YUI Library kann bei SourceForge heruntergeladen werden. Anschließend die entsprechenden Komponenten aus dem build Verzeichnis in ein geeignetes Unterverzeichnis kopieren (hier wird das Verzeichnis js verwendet) und in die HTML Seite einbinden:
<!-- Yahoo! User Interface Library --> <script type="text/javascript" src="js/yahoo/yahoo.js"></script> <script type="text/javascript" src="js/yahoo/event.js"></script> <script type="text/javascript" src="js/yahoo/dom.js"></script> <script type="text/javascript" src="js/yahoo/animation.js"></script>
Ein Akkordion hat immer eine Überschrift und den eigentlichen Inhalt. Im folgenden accordion header und accordion body gennant. Somit wird jeweils ein <div> Element für den accordion header und accordion body benötigt und auch gleich ein entsprechender CSS-Klassenname für das Design und zur späteren Identifikation definiert. Ein Accordion Element (also accordion header und accordion body) wird wiederum mit einem weiteren <div> Element gekapselt und auch wieder mit einem entsprechendem CSS-Klassenname versehen.
Ein vollständiges Accordion Element sieht nun wie folgt aus:
<div class="accordionItem"> <div class="accordionHeader">accordion header</div> <div class="accordionBody">accordion body</div> </div>
Eine letzte Kapselung wird bei einer Menge von accordion items erstellt um dem JavaScript Aufruf zu vereinfachen.
Der vollständige HTML Code für ein Accordion mit drei Elementen sieht wie folgt aus:
<div id="myAccordion" class="accordion"> <div class="accordionItem"> <div class="accordionHeader">accordion header 1</div> <div class="accordionBody" style="height:100px;">accordion body</div> </div> <div class="accordionItem"> <div class="accordionHeader">accordion header 2</div> <div class="accordionBody" style="overflow:auto">accordion body</div> </div> <div class="accordionItem"> <div class="accordionHeader">accordion header 3</div> <div class="accordionBody">accordion body</div> </div> </div>
Durch die Angabe der Höhe des ersten accordion body mit style=”height:100px” wird die Höhe der Akkordion Elemente konfiguriert und gleichzeit das initial geöffnete Element definiert.
Die CSS Klassennamen sind für die jeweiligen Element schon definiert – nun fehlen nur noch die entsprechenden CSS Klassendefinitionen. Generell muss natürlich die Gesamtbreite des Akkordions angegeben werden sonst erscheint dieser über die gesamte verfügbar Breite der Seite. Aber auch der accordion header sowie der accordion body müssen mit Höhen ausgestattet werden, wobei zu beachten ist, dass bei dem accordion body nur das initial aktive Element eine Höhe direkt angegeben bekommt und per default alle anderen eine Höhe von 0 Pixel haben.
<style type="text/css" media="screen"> .accordion { width: 300px; border: 1px solid #999999; font-family: Helvetica,Arial,sans-serif; font-size: 12px; color: #000000; } .accordionHeader { height: 16px; background-color: #CFD8E4; border: 1px solid #999999; font-size: 14px; padding: 1px 0px 1px 3px; cursor: pointer; } .accordionBody { height: 0px; overflow: hidden; padding: 0px 2px; background-color: #EEEEEE; } </style>
Per default ist der accordion body bei meinem Beispiel mit dem style overflow:hidden gesetzt. Das bedeutet, dass auch bei einer größeren Datenmenge für einen accordion body kein Scollbalken erscheint. Möchte man einen Scrollbalken haben so muss der style entweder nur für das entsprechende Akkordion Elemement oder generell in der CSS-Klasse auf overflow:auto gesetzt werden. In meinem Beispiel hat das zweite Akkordion Element einen Scrollbalken.
Es sei noch erwähnt, dass die CSS Definitionen zwecks des guten Stils natürlich in eine eigene CSS Datei ausgelagert werden sollten. In diesem Beispiel werden der Übersicht wegen die CSS Definitionen nicht ausgelagert um den HTML Code direkt mit den dazugehörigen CSS Angaben sehen zu können.
Das JavaScript für die Akkordion Effekt kann in drei Teile aufgeteilt werden.
- Über alle gegebenen Akkordion Elemente iterieren
- Jedes Akkordion Element speichern und das aktive Element finden
- Jedem Element die Akkordion Animation als Click-Event registieren
Der JavaScript Code der nun erstellt wird sollte so allgemein wie nur möglich sein, damit er einfach wiederverwendet werden kann. Aus diesem Grund wurden bei dem Erstellen des HTMLs eindeutige Klassennamen verwendet, die zum einen den Zweck haben eine einheiltiche Gestaltung zu gewährleisten und zum anderen eine einfache Identifikation zu ermöglichen. Zudem wurde dem gesamten Akkordion eine eindeutige ID vergeben. Diese Id wird verwendet um ein Akkordion Objekt zu erstellen.
Wem die kompletten JavaScript Erläuterungen zu viel sind, der kann sich nur das folgende JavaScript Grundgerüst sowie die Erstellung ein solches Akkordion Objektes anschauen und gleich zu den Resourcen springen um entweder nur die accordion.js oder das gesamte Beispiel herunterzuladen. Generell reichen die bisherigen Erläuterungen und das accordion.js aus um ein Akkordion Effekt zu erstellen.
Es wird eine Accordion Funktion erstellt, die als Parameter die Id des Akkordion Rahmen <div> Elements erhält. Schöner Stil ist natürlich, wenn der JavaScript Code in eine separate Datei ausgelagert wird. In diesem Beispiel heisst diese Datei accordion.js. Das Grundgerüst für die Accordion Funktion sieht wie folgt aus:
function Accordion(id) { // Akkordion JavaScript Code }
Um für den oben beschriebenen Akkordion HTML Code den Akkordion Effekt zu geben wird folgender Code genutzt:
<script type="text/javascript" src="js/accordion.js"></script> <script type="text/javascript"> var myAccordions; function init() { accordionWMCities = new Accordion("myAccordion"); } YAHOO.util.Event.addListener(window, 'load', init); </script>
Dabei wird die YUI Event Funktionalität genutzt um das Akkordion Objekt nach dem Erstellen des DOMs mit dem onLoadzu erzeugen.
Nachdem das Erstellen eines Akkordion Objektes geklärt ist werden nun als erstes anhand der übergebenen Akkordion Id die Akkordion Elemente geholt und lokal gespeichert.
In der YUI Library besteht seit der Version 0.10.0 die Möglichkeit Dom Elemente anhand ihres CSS-Klassennamens zu selektieren. Die Funktion ist in er Dom Komponente zu finden (siehe auch JSDoc der DOM-Funktion) und lautet:
Array YAHOO.util.Dom.getElementsByClassName( className, tag, root)
Es würde reichen wenn nur der CSS-Klassenname angegeben wird. Für eine Verbesserung der Performance sollte allerdings der Tag Name der Elemente nach denen gesucht wird (in unserem Fall ist das ein <div>) und ein Start Knoten angegeben werden.
function Accordion(id) { // Speicher das Element der übergebenen ID als Akkordion Container this.accContainer = document.getElementById(id); // Alle Elemente mit der CSS-Klasse 'accordionItem' holen this.accItems = YAHOO.util.Dom.getElementsByClassName("accordionItem", "div", this.accContainer); // default Akkordion body Höhe definieren this.accItemBodyHeight = 0; // Über alle Akkordion Elemente iterieren und jedes einzelne in einem Array speichern for (var i=0; i<this.accItems.length; i++) { ... } }
In der for Schleife wird nun über jedes Akkordion Element (CSS Klasse accordionItem) iteriert und jedes Element sowie deren accordion Header und accordion Body soll gespeichert werden. Gleichzeitig soll geprüft werden ob das aktuelle Element das aktive Element ist. Das aktive Element hat als einzigstes Element eine Höhe im accordion body definiert.
for (var i=0; i<this.accItems.length; i++) { // Aktuelles Akkordion Element als Eltern-Element f?r dazugeh?rigen Header und // Body speichern this.accItems[i].parent = this; // Akkordion Header und Body des aktuellen Akkordion Elements holen und speichern this.accItems[i].header = YAHOO.util.Dom.getElementsByClassName("accordionHeader", "div", this.accItems[i])[0]; this.accItems[i].body = YAHOO.util.Dom.getElementsByClassName("accordionBody", "div", this.accItems[i])[0]; // Prüfen ob das aktuelle Akkordion Element das aktive Element ist (also eine // größere Höhe f?r den accordion body gesetzt hat). Normalerweise sollte nur ein // Element eine Höhe größer 0 Pixel definiert haben. Wenn die Höhe größer der // Höhe des bisherigen aktiven Akkordion oder am Anfang 0 Pixel ist wird dieser // als aktives Element gespeichert. if (this.accItems[i].body.offsetHeight > this.accItemBodyHeight) { this.accItemBodyHeight = this.accItems[i].body.offsetHeight; this.activeItem = this.accItems[i]; this.activeItem.body.style.height = this.accItemBodyHeight + "px"; } ... }
Als letztes muss nur noch die Animation für das Zusammenfahren des aktiven Elements und das Ausdehnen des selektierten Elements definiert werden. Dies wird mit Hilfe der Animation und Event Kompontente der YUI Library implementiert. Auf die Animation Komponente wird in diesem Tutorial nicht weiter eingegangen. Dieses Thema wird separat in einem weiteren Tutorial behandelt.
for (var i=0; i<this.accItems.length; i++) { ... // Einen Click Event Listener für jeden accordion header registrieren YAHOO.util.Event.addListener(this.accItems[i].header, "click", function(){ // Wenn auf das aktive Element geklickt wurde - nichts machen if(this.parent.activeItem == this){ return; } // Für das aktive Element eine "Schrumpf" Animation definieren var shrinkLastAccAnim = new YAHOO.util.Anim(this.parent.activeItem.body, { height:{from:this.parent.accItemBodyHeight, to:0}}, 0.5); // Für das angeklickte Elment eine "Ausdehnen" Animation definieren var expandNewActiveAccAnim = new YAHOO.util.Anim(this.body, { height:{from:0, to:this.parent.accItemBodyHeight}}, 0.5); // Selektiertes Element als aktives Element setzen expandNewActiveAccAnim.onStart.subscribe(function() { this.parent.activeItem = this; }, this, true); // Animation starten shrinkLastAccAnim.animate(); expandNewActiveAccAnim.animate(); }, this.accItems[i], true); }
Der gesamte JavaScript Code für den Accordion Effekt ist im folgenden Listing zu erkennen. Dieser ist ausführlich kommentiert und sieht auf den ersten Blick evtl. komplexer aus als er wirklich ist. Die Hälfte des Listings besteht aus Kommentaren. Das JavaScript für den Akkordion Effekt kann auch direkt als Datei heruntergeladen werden (siehe Ressourcen).
function Accordion(id) { // Speicher das Element der ?bergebenen ID als Akkordion Container this.accContainer = document.getElementById(id); // Alle Elemente mit der CSS-Klasse 'accordionItem' holen this.accItems = YAHOO.util.Dom.getElementsByClassName("accordionItem", "div", this.accContainer); // default Akkordion body H?he definieren this.accItemBodyHeight = 0; // ?ber alle Akkordion Elemente iterieren und jedes einzelne in einem Array speichern for (var i=0; i<this.accItems.length; i++) { // Aktuelles Akkordion Element als Eltern-Element f?r dazugeh?rigen Header und // Body speichern this.accItems[i].parent = this; // Akkordion Header und Body des aktuellen Akkordion Elements holen und speichern this.accItems[i].header = YAHOO.util.Dom.getElementsByClassName("accordionHeader", "div", this.accItems[i])[0]; this.accItems[i].body = YAHOO.util.Dom.getElementsByClassName("accordionBody", "div", this.accItems[i])[0]; // Prüfen ob das aktuelle Akkordion Element das aktive Element ist (also eine // größere Höhe f?r den accordion body gesetzt hat). Normalerweise sollte nur ein // Element eine Höhe größer 0 Pixel definiert haben. Wenn die Höhe größer der // Höhe des bisherigen aktiven Akkordion oder am Anfang 0 Pixel ist wird dieser // als aktives Element gespeichert. if (this.accItems[i].body.offsetHeight > this.accItemBodyHeight) { this.accItemBodyHeight = this.accItems[i].body.offsetHeight; this.activeItem = this.accItems[i]; this.activeItem.body.style.height = this.accItemBodyHeight + "px"; } // Einen Click Event Listener f?r jeden accordion header registrieren YAHOO.util.Event.addListener(this.accItems[i].header, "click", function(){ // Wenn auf das aktive Element geklickt wurde - nichts machen if(this.parent.activeItem == this){ return; } // F?r das aktive Element eine "Schrumpf" Animation definieren var shrinkLastAccAnim = new YAHOO.util.Anim(this.parent.activeItem.body, { height:{from:this.parent.accItemBodyHeight, to:0}}, 0.5); // F?r das angeklickte Elment eine "Ausdehnen" Animation definieren var expandNewActiveAccAnim = new YAHOO.util.Anim(this.body, { height:{from:0, to:this.parent.accItemBodyHeight}}, 0.5); // Selektiertes Element als aktives Element setzen expandNewActiveAccAnim.onStart.subscribe(function() { this.parent.activeItem = this; }, this, true); // Animation starten shrinkLastAccAnim.animate(); expandNewActiveAccAnim.animate(); }, this.accItems[i], true); } // Letzte Prüfung, falls mehrere Elemente eine Höhe angegeben haben. Es wird // nur das aktive Element offen gelassen. Alle anderen Akkordion Elemente // erhalten die Höhe 0 Pixel. for(var i=0; i<this.accItems.length; i++){ if(this.activeItem != this.accItems[i]){ this.accItems[i].body.style.height = 0 + "px"; } } };
Das hier beschriebene Beispiel kann noch einmal separat auf einer eigenen HTML Seite angesehen werden: Link
Zudem kann das gesamte Beispiel komplett zum entpacken heruntergeladen werden: AkkordionBeispiel.zip
Oder auch nur der Akkordion JavaScript: accordion.js
Viel Spass beim Ausprobieren.
