Java(-Script) Workshops -> Browserunabhängiges Popup-Menü
Kleines Popup-Menü mit JavaScript
In diesem WS werde ich ein kleines Menüsystem vorstellen, was in JavaScript geschrieben ist. Dabei soll hier nicht ein grafisch perfektes und Menü gebastelt werden, in dass der User nur noch seinen Text einfügt, sondern hier geht es vielmehr um das Verstehen des Konzeptes als um die genaue grafische Umsetzung - die ist nämlich bei mir um einiges länger geworden als das eigentliche Skript. Alles klar? Dann kann's ja losgehen.
Der Anfang: HTML-Layout
Für den Anfang bauen wir uns einfach an den Anfang der Seite eine Tabelle, die stellt später das Menü dar. Ich nehme jetzt als Beispiel einfach mal drei Menü-Überschriften, die jeweils ein zugehöriges Popup mit jeweils drei Einträgen haben. Das kann natürlich alles verändert werden, es geht ja hier nur um die Demonstration.
Wie man Tabellen macht, sollte man hoffentlich wissen, wenn man diesen WS liest. Wenn nicht, empfehle ich euch, euch dieses Wissen zuerst anzueignen.
Die Menü-Tabelle
<table>
<tr>
<td>Punkt 1</td>
<td>Punkt 2</td>
<td>Punkt 3</td>
</tr>
<tr>
<td>Item 1.1<br>Item 1.2<br>Item 1.3</td>
<td>Item 2.1<br>Item 2.2<br>Item 2.3</td>
<td>Item 3.1<br>Item 3.2<br>Item 3.3</td>
</tr>
</table>
Die sollte soweit erstmal jeder verstehen. Dazu empfiehlt sich noch eine Prise CSS-Formatierung, dann kann das so aussehen wie bei meinem Beispiel.
IDs und die "Würze"
Bei der Tabelle war ja noch nichts auch nur annähernd dynamisch. Damit wir das aber dynamisch machen können, müssen wir den einzelnen Menüs erstmal eindeutige IDs zuweisen. Außerdem verhindern wir erstmal die Anzeige der Popups -> Die sollen ja später dynamisch eingeblendet werden. Außerdem wird die ganze Tabelle mit dem style-Attribut position:absolute; versehen, damit das ganze sich nachher über dem Text befindet. Der veränderte Code lautet jetzt zum Beispiel so:
<table style="position:absolute; width:100%">
<tr>
<td>Punkt 1</td>
<td>Punkt 2</td>
<td>Punkt 3</td>
</tr>
<tr>
<td id="menupopup1" style="visibility:hidden;">Item 1.1<br>Item 1.2<br>Item 1.3</td>
<td id="menupopup2" style="visibility:hidden;">Item 2.1<br>Item 2.2<br>Item 2.3</td>
<td id="menupopup3" style="visibility:hidden;">Item 3.1<br>Item 3.2<br>Item 3.3</td>
</tr>
</table>
Die veränderten Stellen habe ich herausgehoben. Mit etwas CSS-Formatierung kann das ganze dann zum Beispiel so aussehen.
Jetzt wird's dynamisch
So jetzt geht's an's eingemachte. Das Menü soll im Endeffekt so aussehen: Wenn der User mit der Maus über eine von den 3 Menüköpfen fährt, wird automatisch das dazugehörige Menü angezeigt. Wenn der User mit der Maus den Kopf wieder verlässt, soll das Menü nach einer geringen Zeitspanne wieder versteckt werden, es sei denn, der User fährt mit der Maus auf genau dieses Menü. (Verstanden?)
Ich habe dies mit 4 Funktionen, einem Array und einer veränderbaren Variable gelöst. In dem assoziativen Array mit dem Namen popped speichere ich den Zustand der einzelnen Menüs, sprich ob diese zu sehen sein sollen oder nicht. Diese Variable wird beim Überfahren eines Menüelements mit der Maus auf true gesetzt, beim verlassen auf false. Die Variable depopdelay speichert die Verzögerung, bis ein Menü wieder zugeht. Diese kann man aus Designgründen verändern, aber auch aus praktischen Gründen. Das Menü muss nämlich nicht zwangsläufig in unmittelbarer Nähe des Menükopfes aufpoppen, und wenn das der Fall sein sollte, muss der User ja Zeit haben die Maus dorthin zu bewegen.
Die Funktionen sind die folgenden:
menupopup(ID des Menüs) -> Poppt ein Menü auf.
depopper(ID des Menüs) -> Startet den Countdown zum Schließen des Menüs
closepopup(ID des Menüs) -> Versteckt das Menü
staypopped(ID des Menüs) -> Verhindert das Zuklappen des Menüs, wenn der User mit der Maus das Menü "betreten" hat.
Und so sehen die Funktionen im Einzelnen aus:
function menupopup(popup) {
popped[popup]=true;
document.getElementById(popup).style.visibility="visible";
}
Wie man sieht, benutzt die Funktion die Funktion document.getElementById, um ein sogenanntes HTML-Elementobjekt für die Tabellenzelle mit der übergebenen ID zu erstellen. Dieses hat ein Unterobjekt style, dessen Eigenschaft visibility dann verändert werden kann. Gleichzeitig wird in das Array geschrieben, dass das Menü offenbleiben soll.
function depopper(popup) {
window.setTimeout("closepopup('"+popup+"')",depopdelay);
popped[popup]=false;
}
function closepopup(popup) {
if(popped[popup]==false)
document.getElementById(popup).style.visibility="hidden";
}
Diese Funktionen gehören eng zusammen. Man hätte das auch in einer Funktion schreiben können, aber so ist es übersichtlicher:
In der Funktion depopper wird ein Timeout gesetzt (das heißt, nach einer Zeit von depopdelay Millisekunden wird die funktion closepopup mit der ID des Menüs als Parameter aufgerufen). Außerdem wird in das Array geschrieben, dass das Menü geschlossen werden kann (Logisch, denn diese Funktion wird nur beim Verlassen des Menükopfes aufgerufen)
Die Funktion closepopup ist ganz einfach. Hier wird einfach überprüft (indem der Wert im Array popped überprüft wird), ob das Menü geschlossen werden kann, und wenn ja, dann wird (wieder mittels document.getElementById) das Menü versteckt.
function staypopped(popup) {
popped[popup]=true;
}
Diese Funktion ist nun wahrlich einfach: Hier wird einfach nur in das Array geschrieben, dass das Menü offenbleiben soll.
Und nochmal der ganze Code zum Kopieren
<!-- Popup Menu Bar v1.0 by Triple-M -->
<script type="text/javascript">
<!--
var depopdelay=10; // Delay bis zum Schließen
var popped=new Array(); // Status der Menüs
function menupopup(popup) {
popped[popup]=true;
document.getElementById(popup).style.visibility="visible";
}
function depopper(popup) {
window.setTimeout("closepopup('"+popup+"')",depopdelay);
popped[popup]=false;
}
function closepopup(popup) {
if(popped[popup]==false)
document.getElementById(popup).style.visibility="hidden";
}
function staypopped(popup) {
popped[popup]=true;
}
//-->
</script>
Feinschliff: Der Aufruf
Auch der beste Code nutzt bekanntlich nichts wenn er nicht aufgerufen wird. Also müssen wir das noch dazufügen. Und zwar nach diesem Schema:
MenüKopf
onMouseOver -> popup
onMouseOut -> depopper
Menü
onMouseOver -> staypopped
onMouseOut -> depopper
Beim "Betreten" des Menükopfes wird das Menü geöffnet, beim "Betreten" des Menüs bleibt dieses offen (natürlich nur dann wenn es schon offen ist, sonst passiert nichts)
Beim "Verlassen" des Menükopfes oder des Menüs wird der Timeout gesetzt.
Jede dieser Funktionen bekommt als Parameter immer die ID des Menüs mit, welches gemeint ist, also für die erste Spalte 'menu1'.
Der geänderte HTML-Code lautet dann so:
<table style="position:absolute; width:100%">
<tr>
<td onMouseOver="menupopup('menu1')" onMouseOut="depopper('menu1')">Punkt 1</td>
<td onMouseOver="menupopup('menu2')" onMouseOut="depopper('menu2')">Punkt 2</td>
<td onMouseOver="menupopup('menu3')" onMouseOut="depopper('menu3')">Punkt 3</td>
</tr>
<tr>
<td id="menu1" style="visibility:hidden;" onMouseOver="staypopped('menu1')" onMouseOut="depopper('menu1')">Item 1.1<br>Item 1.2<br>Item 1.3</td>
<td id="menu2" style="visibility:hidden;" onMouseOver="staypopped('menu2')" onMouseOut="depopper('menu2')">Item 2.1<br>Item 2.2<br>Item 2.3</td>
<td id="menu3" style="visibility:hidden;" onMouseOver="staypopped('menu3')" onMouseOut="depopper('menu3')">Item 3.1<br>Item 3.2<br>Item 3.3</td>
</tr>
</table>
Die geänderten Stellen sind wieder hervorgehoben.
Und so sieht das Ganze dann aus.
Die einzelnen Items in den Menüs kann man natürlich auch einfach zu Links machen:
<td id="menu1" style="visibility:hidden;" onMouseOver="staypopped('menu1')" onMouseOut="depopper('menu1')"><a href="seite11.html">Item 1.1</a><br><a href="seite11.html">Item 1.2</a><br><a href="seite11.html">Item 1.3</a></td>
Aber das sollte sowieso klar gewesen sein, oder?
Das Menü habe ich unter dem IE 5+6, Mozilla 1.2.1 und Opera 7 getestet - Da funktioniert es ohne Probleme.