János Rácz
In Ordnung, wir haben es fast geschafft. Wenn Sie den Code aus Teil I des Tutorials genau jetzt in eine Website einbauen, wird er höchstwahrscheinlich – wenn Sie alles richtig gemacht haben – einfach nur gut funktionieren. Um aber sicherzugehen, dass alles reibungslos läuft, lassen Sie uns diese globalen Variablen loswerden. Diese in einer Klasse zu verstecken ist immer eine gute Idee, damit sie nicht mit anderem JavaScript Code kollidieren.

Das Sliding-Menü aus Teil I des Workshops – Demo
Das ist ganz besonders wichtig, wenn Sie andere JavaScript-Schnipsel aus verschiedenen Quellen zu Ihrer Seite hinzugefügt haben. Stellen Sie sich vor, zwei Programmierer würden einer ihrer globalen Variablen den gleichen Namen geben. Wann auch immer Sie mit der einen interagieren würden, würde sich das automatisch auf die andere auswirken. Das wäre ein Chaos!
Klassen und Variablen einsetzen
Also erstellen wir nun die Klasse SlidingMenu und verwenden active_menu und is_animation_running als ihre Variablen.
Dieser Ansatz erlaubt es Ihnen auch, das Slide-Menü öfter als einmal auf der Seite zu verwenden. Alles, was Sie tun müssen, ist für jedes animierte Menü eine neue Instanz von SlidingMenu zu erstellen. Und wenn wir schon einmal dabei sind, können wir die Slidefunktion genausogut SlidingMenu zuordnen, so dass sie ihre Variablen, falls erforderlich, direkt modifizieren und auf sie zugreifen kann.
function SlidingMenu ()
{
// Let's make these class variables so that other functions (i.e. slide) can access them.
this.is_animation_running = false;
this.active_menu = $($( ".menu .menu_slider" )[0]);
// We do the bindings on object creation.
var self = this;
$( ".menu .menu_button" ).bind( "click", self, on_click ); // Menu button click binding.
// Do the slide.
this.slide ( 253 );
}
SlidingMenu.prototype.slide = slide;
function slide ( width )
{
this.is_animation_running = true;
var self = this;
this.active_menu.animate (
{ 'width' : width }, // We replaced the specific value with the second parameter.
1000,
function ()
{
self.is_animation_running = false; // We set is_animation_running false after the animation finishes.
}
);
}
function on_click ( event )
{
// Notice we access the SlidingMenu instance through event.data!
if ( $(this).next()[0] == event.data.active_menu[0] )
{
return;
}
if ( event.data.is_animation_running )
{
return;
}
// Get the item next to the button.
var menu_slider = $(this).next();
// First slide in the active_menu.
event.data.slide ( 0 );
// Set the active menu to the current image.
event.data.active_menu = menu_slider;
// Then slide out the clicked menu.
event.data.slide ( 253 );
}
var sl = new SlidingMenu(); // We pass the three parameters when creating an instance of the menu.
Der vorstehende Code bedarf einiger Erklärung. Es gibt drei wichtige Blöcke, also lassen Sie sie uns einen nach dem anderen anschauen.
Die Klasse SlidingMenu
function SlidingMenu () // Our new class
{
// Let's make these class variables so that other functions (i.e. slide) can access them.
this.is_animation_running = false;
this.active_menu = $($( ".menu .menu_slider" )[0]);
// We do the bindings on object creation.
var self = this;
$( ".menu .menu_button" ).bind( "click", self, on_click ); // Menu button click binding.
// Do the slide.
this.slide ( 253 );
}
Anders als viele andere Programmiersprachen hat JavaScript kein class-Schlüsselwort für die Erstellung von Klassen. Aber wir können einfach Objekte erstellen, die ihre eigenen Variablen und Methoden haben, indem wir ein reguläres JavaScript-Objekt erstellen.
Also definieren wir hier im Prinzip eine Funktion, SlidingMenu, und in diese Funktion packen wir alles, was wir in anderen Sprachen in einen regulären Klassenkonstruktor setzen würden.
Wir definieren zuerst die gleichen zwei Variablen, die wir vorher benutzt haben, is_animation_running und acitve_menu. Mit dem Schlüsselwort this stellen wir sicher, dass sie zu der bestimmten Klasseninstanz gehören.
Der nächste Teil mag zunächst nicht offensichtlich sein:
var self = this; $( ".menu .menu_button" ).bind( "click", self, on_click );
Um das zu verstehen, müssen wir uns ein wenig darüber unterhalten, wie jQuery mit Ereignissen umgeht.
jQuery Event Handling 101 (zumindest, was wir hier wissen müssen)
Kurz gesagt verwendet jQuery die Methode bind, um Eventlistener zu DOM-Elementen hinzuzufügen. (Alternativ können Sie die Methode live verwenden, die Eventlistener aktualisiert, wenn dem Dokument neue Elemente hinzugefügt werden.)
Die Basisanwendung von bind erfordert zwei Parameter: Einen Ereignistyp (etwa click oder mouseover) und eine Funktion, das heißt Callback-Funktion, die ausgeführt wird, wenn der vorgegebene Ereignistyp beim DOM-Element eintritt.
Und das ist der Punkt, an dem das Schlüsselwort this ins Spiel kommt, denn in der Callback-Funktion wollen wir häufig das DOM-Objekt referenzieren, auf dem das Ereignis stattfand. jQuery macht es sehr bequem, das zu tun, wir brauchen nur this zu verwenden.
Praxisbeispiel – Bildelement wechseln
Lassen Sie uns zum Beispiel sagen, dass wir ein Bildelement austauschen wollen, wenn der User darauf klickt. Um das zu tun, können wir so etwas wie das hier schreiben:
$("#example_img").bind ( "click", change_image );
function change_image ( event )
{
this.src = "images/another_img.png";
}
Im obigen Beispiel verwenden wir das Schlüsselwort this, um das DOM-Objekt zu referenzieren. Für einfache Anwendungen ist das sehr bequem, bei komplizierteren könnten Sie jedoch auf Probleme stoßen.
Wie in dem Beispiel möchten wir irgendwie auf die Variablen der Instanz SlidingMenu zugreifen. Da das Schlüsselwort this bereits verwendet wird, um das DOM-Objekt zu referenzieren, müssen wir einen anderen Weg finden.
Glücklicherweise ist das dank jQuery ziemlich einfach zu erledigen. Zu dem Zweck übergeben wir einen anderen Parameter an die bind-Funktion, der genau zwischen dem Ereignistyp und der Callback-Funktion platziert wird. Dieser Parameter muss ein Objekt sein.
Sie haben sicherlich den Parameter event in der obigen Funktion change_image bemerkt. An jede Callback-Funktion wird automatisch ein event-Parameter übergeben, der ein paar wertvolle Informationen enthält, so zum Beispiel, welches Element angeklickt wurde. Und mit dem erweiterten Abruf der Funktion bind können wir das Instanzobjekt SlidingMenu auch durch den Eventparameter übergeben. Mit event.data können wir dann auf dieses Objekt zugreifen.
Hier ist ein einfaches Beispiel:
function ImageData () // This will be an object that contains information about an image, much like our SlidingMenu class contains information about the sliding menu.
{
this.width = "500";
this.height = "200";
this.src = "images/example_image.png";
}
// We create an instance of ImageData.
var image_instance = new ImageData();
// We bind the change_image function to the click event, passing along the image_instance data object as well.
$("#example_image").bind ( "click", image_instance, change_image );
// The callback function.
function change_image ( event )
{
this.src = event.data.width; // event.data refers to the image_instance object
this.src = event.data.height;
this.src = event.data.src;
}
Dieses Beispiel illustriert gut, wie wir sowohl auf das DOM-Element, auf dem das Ereignis stattfand, als auch auf das Datenobjekt, das wir durchgereicht haben, zugreifen können. Auf das Erstere greifen wir durch das Schlüsselwort this zu und auf das Letztere durch event.data.
Nun macht es letztendlich Sinn, warum wir diese erweiterte Version der Funktion call verwendet haben, als wir das click-Ereignis an die Buttons gebunden haben. Und weil this sich in diesem Zusammenhang immer auf das DOM-Element beziehen wird, verwendeten wir die self-Variablen als Ersatz, um die Instanz SlidingMenu an die Funktion Callback zu übergeben.
Hier noch einmal:
var self = this; $( ".menu .menu_button" ).bind( "click", self, on_click );
Weiter geht’s
Der letzte Teil in unserer Klassendefinition lässt einfach nur das erste Feld hinausgleiten, indem sie die Methode slide verwendet. Aber da wir eine solche Funktion bisher noch nicht definiert haben, wird die Zeile unter der Klassendefinition auch wichtig:
SlidingMenu.prototype.slide = slide;
Wir verwenden den Prototypmechanismus von JavaScript, um unser Objekt SlidingMenu mit der Methode slide zu erweitern.
Dieser Ansatz hat zwei Hauptvorteile:
- Erstens kann die Slidefunktion nun direkt auf die Variablen aller Klasseninstanzen zugreifen, indem sie das Schlüsselwort
thisverwendet. (Da keine Ereignisverarbeitung direkt in diese Funktion involviert ist, bezieht sichthisnun auf die InstanzSlidingMenu. Beion_clickwerden Sie sehen, dass wir mitevent_dataauf sie werden zugreifen müssen. - Zweitens verbessert die Verwendung von
prototypeanstelle des direkten Schreibens in der Klasse die Speichernutzung, wenn wir mehr als eine Instanz vonSlidingMenuerstellen, denn wir müssen die Funktionenslidenicht jedes Mal, wenn wir eine neue Instanz erstellen, neu erschaffen: Es wird immer die externe Funktion verwendet.
Die Slide-Funktion
Wie wir bereits diskutiert haben, ist slide für das Ein- und Ausfahren der Felder verantwortlich. Sie wird von der Funktion on_click aufgerufen (siehe unten) und verwendet dieselben Parameter wie zuvor:
function slide ( width )
{
this.is_animation_running = true;
var self = this;
this.active_menu.animate (
{ 'width' : width },
this.effect_duration,
function ()
{
self.is_animation_running = false;
}
);
}
Sie sehen, dass wir this vor jede Variable setzen und diese sich nun auf die Variablen der Klasseninstanz beziehen. Auf diese Weise müssen wir die Variablen nicht als Funktionsparameter übergeben, um auf sie zuzugreifen oder sie sogar zu modifizieren. Und ganz egal, wie viele Instanzen von SlidingMenu wir erstellen, sie werden sich immer auf die richtigen Variablen beziehen.
Die Variable self
Sie haben vielleicht bemerkt, dass wir eine Variable eingeführt haben, die self genannt wird. Im Prinzip haben wir das aus dem gleichen Grund getan, wie in unserer Klassendefinition: Weil jQuery diesen letzten Parameter ähnlich wie die Ereignisverarbeitung behandelt.
Hätten wir stattdessen this verwendet, würde sich dieser auf das DOM-Objekt beziehen. Probieren Sie es aus: Es wird nicht richtig funktionieren. Mit der Einführung der Variablem self laufen die Animationen wie erwartet.
Die letzte erwähnenswerte Sache ist, dass wir den Parameter menu_slider durch die Variable der Klasseninstanz active_menu ersetzt haben. Also können wir diese Variable von nun an von überall aus setzen und sie wird das aktuelle active_menu automatisch animieren. Das dient nur der Bequemlichkeit, einen Parameter weniger zu übergeben.
Die Funktion on_click
Lassen Sie uns zuletzt die Funktion on_click betrachten. Hier setzten wir den gesamten Code hinein, der beschreibt, was passiert, wenn der User auf einen Menüpunkt klickt.
Die Funktion führt die gleichen Überprüfungen aus wie vorher und verwendet die Funktion slide, um Menüobjekte zu verbergen oder sichtbar zu machen. Diese Methode greift durch die Variable event.data, die wir in unserer Klassendefinition weitergegeben haben, auf die Klassenvariablen zu.
Jetzt können Sie auch sehen, dass wir nur einen Parameter an unsere modifizierte slide-Funktion übergeben (die gewünschte Breite des Elements), um zu ermitteln, ob das Menü eingefahren oder ausgefahren werden soll. Jedoch wird auf das Element, das animiert werden soll, direkt durch die Variable acitve_menu zugegriffen.
function on_click ( event )
{
// First check if the active_menu button was clicked. If so, we do nothing. ( return )
if ( $(this).next()[0] == event.data.active_menu[0] ) // Remember, active_menu refers to the image ( thus next() ).
{
return;
}
// Check if animation is running. If it is, we interrupt.
if ( event.data.is_animation_running )
{
return;
}
// Get the item next to the button.
var menu_slider = $(this).next();
// First slide in the active_menu.
event.data.slide ( 0 );
// Set the active menu to the current image.
event.data.active_menu = menu_slider;
// Then slide out the clicked menu.
event.data.slide ( 253 );
}
Der Feinschliff
An diesem Punkt sollte unser Slide-Menü genauso funktionieren, wie wir wollen und wir müssen uns nicht darum sorgen, ob es mit anderem JavaScript Code in Konflikt gerät.
Es gibt noch eine letzte Sache zu tun, bevor wir einpacken, und zwar müssen wir die Klasse SlidingMenü ein bisschen flexibler machen, denn sie ist viel zu starr, so wie sie jetzt ist:
- Sie funktioniert nur mit einem Container mit dem Klassennamen
menu. - Sie funktioniert nur mit Menübildern, die 253 Pixel lang sind.
- Sie funktioniert nur, wenn die Dauer der Animation auf 1 Sekunde eingestellt ist.
Um das zu ändern, übergeben wir drei weitere Variablen an den SlidingMenu-Konstruktor:
container_nameenthält die Klasse (oderid, siehe unten) des Menücontainersdiv,menu_slider_lengthbestimmt die Breite der Bilder, wenn sie ausfahren,durationlegt die Dauer der Animation in Millisekunden fest.
function SlidingMenu ( container_name, menu_slider_width, duration ) // Note the new parameters.
{
var self = this;
$( container_name + " .menu_button" ).bind ( "click", self, on_click ); // We bind to the specified element.
this.effect_duration = duration; // New variable 1.
this.menu_slider_width = menu_slider_width; // New variable 2.
this.is_animation_running = false;
this.active_menu = $($( container_name + " .menu_slider" )[0]);
this.slide ( this.menu_slider_width ); // We replaced 253 with the arbitrary variable.
}
SlidingMenu.prototype.slide = slide;
// Function to render the animation.
function slide ( width )
{
this.is_animation_running = true;
this.active_menu.animate (
{ 'width' : width },
this.effect_duration, // Replace 1000 with the duration variable.
function ()
{
this.is_animation_running = false;
}
);
}
function on_click ( event )
{
if ( $(this).next()[0] == active_menu[0] )
{
return;
}
if ( event.data.is_animation_running )
{
return;
}
var menu_slider = $(this).next();
event.data.slide ( 0 );
this.active_menu = menu_slider;
event.data.slide ( event.data.effect_duration ); // Slide with the specified amount.
}
var sl = new SlidingMenu( ".menu", 253, 1000 ); // We pass the three new parameters when creating an instance.
Wo nötig, haben wir die Variablen einfach durch drei neue ersetzt. Sie sehen, dass wir hier noch viel mehr Anpassungen vornehmen könnten, zum Beispiel nicht nur den Namen des Hauptcontainers .menu ersetzen, sondern auf der ganzen Linie auch die, die wir .menu_button und menu_slider genannt haben. Aber das überlassen wir Ihnen.
Wenn Sie wollten, könnten Sie für den Hauptcontainer sogar eine id festlegen (etwa #menu). Plötzlich ist alles ein wenig freundlicher und flexibler geworden.
Natürlich ist es nur dann sinnvoll, die Breite der Bilder zu ändern, wenn Sie auf Ihrer Website Grafiken verwenden, die nicht genau 253 Pixel breit sind. Dann können Sie einfach den Konstruktor SlidingMenu mit der richtigen Breite aufrufen und ihre Bilder werden perfekt dargestellt.
Wir werden ein wenig komplexer
Eine andere Sache, die ich am Anfang dieses Tutoriols erwähnt habe ist, dass, da wir uns nur um die Container der Elemente sorgen müssen, menu_slider kann jedes Element sein, das die Klasse menu_slider hat. Bei einem komplexeren Beispiel könnte menu_slider also ein div sein, das eine Liste von Untermenüpunkten enthält:

Ein Klick aufs Bild öffnet die Demo.
So sieht es viel besser aus, oder? Natürlich würden Sie, wenn Sie das Menü in der Praxis einsetzen, einen Link zu jedem dieser Listenpunkte hinzufügen, so dass der User, wenn er darauf klickt, die entsprechende Seite lädt. Das haben wir hier bei dieser Demo ausgespart.
Nebenbei, wenn Sie nicht möchten, dass der Text mit der Breite des Containers schrumpft (wie im obigen Beispiel), dann fügen Sie einfach width: 253px; zu Ihrer CSS-Datei hinzu und ersetzen Sie die Angabe “253px” einfach durch die gewünschte Breite.
Hier ist das ganze zusätzliche CSS, das ich für die obige Demo mit den Untermenüpunkten verwendet habe:
.menu .menu_slider ul {
position : relative;
top : -100px;
left : -35px;
font-size : 12px;
}
.menu .menu_slider img {
width : 253px;
height : 158px;
}
.menu .menu_slider ul li {
list-style : none;
background : #fff;
color : #333;
cursor : pointer;
}
.menu .menu_slider p {
width : 253px;
margin-left : 5px;
}
Das Einzige, das hier erwähnenswert ist, ist die Schriftgröße. Da wir Menübreite und -höhe und so ziemlich alles andere in Pixel definiert haben, ist es besser, auch die Schriftgröße auf eine bestimmte Zahl einzustellen, damit die Ansicht durch alle verschiedenen Browser hindurch konsistent ist.
Außerdem werden Sie sehen, dass die Menüpunkte beim Mouseover klarer und schärfer werden. Das wird durch das Verändern der Deckkraft beim Darüberfahren erreicht. Anstatt verschiedene CSS-Hacks für die Cross-Browser-Kompatibilität zu verwenden, trauen wir jQuery in dieser Sache: Verwenden Sie einfach die Methode fadeTo, um ab- oder aufzublenden:
$(".menu .menu_slider ul li").bind ( "mouseover", function () {
$(this).fadeTo ( "fast", "1.0" );
} );
$(".menu .menu_slider ul li").bind ( "mouseout", function () {
$(this).fadeTo ( "fast", "0.8" );
} );
// This line is used to make them fade out by default.
$(".menu .menu_slider li").fadeTo ( "fast", 0.8 );
Der komplette Code zum Herunterladen
Glückwunsch! Sie haben es geschafft! Jetzt sollten Sie ein funktionierendes JavaScript Slide-Menü haben. Und, noch wichtiger, Sie sollten ein wenig Verständnis davon haben, wie es funktioniert und wie Sie Ihre eigenen Ideen in dieses Modell einbeziehen können. Hoffentlich haben Sie in diesem Tutoriol etwas Nützliches gelernt. Um nun die Belohnung einzuheimsen, müssen Sie sich nur noch den kompletten Code schnappen, den wir zuvor in Einzelblöcken erstellt haben, und ihn im jQuery-Stil auf Page Load laden:
$(document).ready( function() {
// All code goes here.
});
Um es noch einfacher zu machen, sind hier alle Quelldateien sowohl für das einfache Beispiel aus Teil I des Tutorials als auch für die komplexen Beispiele des zweiten Teils, die Sie oben gesehen haben:
Voilà. Nun können Sie nach eigenem Belieben experimentieren, sehen, wie es funktioniert und die notwendigen Anpassungen vornehmen. Wenn Sie zum Beispiel statischen Inhalt haben, möchten Sie vielleicht den Trigger von click auf mouseover ändern, so dass das Menü mit dem Gleiten beginnt, sobald sich die Maus darüber befindet. Auf diese Weise können Seiten geladen werden, wenn der User auf die Bilder oder Buttons klickt. Oder Sie können mit verschiedenen Effekten spielen: Vielleicht beim Mouseover einen netten Rahmen um die Bilder setzen. Das liegt ganz bei Ihnen. Viel Spaß!
Ausblick
Nun, wir können hier immer noch eine Menge tun. Optimierung und Anpassung haben wir noch immer nicht abgedeckt. Und natürlich ist die Animation immer noch ein einfacher Slide. Wie ich schon sagte, könnten Sie den gleichen Effekt mit jQuerys Plug-in accordion erreichen.
Aber das ist der Punkt, an dem es interessant wird. Jetzt, wo wir ein solides Fundament haben, können wir über einige fortgeschrittene Effekte nachdenken, um unsere kleine Anwendung noch einfacher in der Handhabung zu machen. Im nächsten Teil werden wir einige dieser Effekte einbauen und das Menü weiter optimieren.
(mm),
Weitere Beiträge:
- 5 Ideen wie Sie wiederkehrende Arbeitsschritte & Marketingprozesse gewinnbringend im Internet automatisieren! Ein Gastbeitrag von Robert Nabenhauer.
- Wachstum durch Facebook-Gewinnspiele: Wie Sie über Facebook virale Gewinnspiele & eine schnell wachsende Fangemeinde aufbauen
- Wie Sie aufmerksamkeitsstarke Prelaunch-, Launch- und Relaunch-Szenarien aufbauen und dabei Viralität, Spannung & Kaufkraft erzeugen
- Wie Sie waschechte Iphone-Apps mit PhoneGAP entwickeln, um am lukrativen App-Markt mitzumischen
- Wie Sie Ihr Shop-Sortiment so präsentieren, dass der Kunde in Zukunft mehr findet und eher kauft! Ein Gastbeitrag von Nicolas Schmidt-Voigt.
- 11 faszinierende BuddyPress-Plugins, um kostenlos aus WordPress ein soziales Netzwerk zu zaubern
- Die Vorboten einer neuen Internet-Industrie! Ein exklusiver Rückblick & Blick hinter die Kulissen der Clickbank-Exchange 2011 in New York.


Hallo,
es ist zwar sehr sinnvoll, keine globalen Variablen zu verwenden, aber warum werden dann globale Funktionen benutzt? Das ist unsauber, vor allem, da das prototype ja direkt drüber steht.
Eine einfaches und direktes
SlidingMenu.prototype.slide = function ( width ) {
…
}
halte ich hier für deutlich sinnvoller.
Soweit ich das beurteilen kann, handelt es sich nicht um eine globale Funktion, da die Funktion beziehungsweise Methode “slide” in die Klasse “SlidingMenu” integriert ist. Siehe dazu auch folgende Erläuterung des Autors:
Zitat: ” Der letzte Teil in unserer Klassendefinition lässt einfach nur das erste Feld hinausgleiten, indem sie die Methode slide verwendet. Aber da wir eine solche Funktion bisher noch nicht definiert haben, wird die Zeile unter der Klassendefinition auch wichtig:
SlidingMenu.prototype.slide = slide;
Wir verwenden den Prototypmechanismus von JavaScript, um unser Objekt SlidingMenu mit der Methode slide zu erweitern.
Dieser Ansatz hat zwei Hauptvorteile:
Erstens kann die Slidefunktion nun direkt auf die Variablen aller Klasseninstanzen zugreifen, indem sie das Schlüsselwort this verwendet. (Da keine Ereignisverarbeitung direkt in diese Funktion involviert ist, bezieht sich this nun auf die Instanz SlidingMenu. Bei on_click werden Sie sehen, dass wir mit event_data auf sie werden zugreifen müssen.
Zweitens verbessert die Verwendung von prototype anstelle des direkten Schreibens in der Klasse die Speichernutzung, wenn wir mehr als eine Instanz von SlidingMenu erstellen, denn wir müssen die Funktionen slide nicht jedes Mal, wenn wir eine neue Instanz erstellen, neu erschaffen: Es wird immer die externe Funktion verwendet.”
Hallo, das ist wirklich ein Tolles Menü, gibt es da eine möglichkeit das ganze anstelle Horizontal zu betreiben einfach Vertikal laufen zu lassen.
oder lässt sich das nicht so einfach bewerkstelligen?