Pulldown-Menüs


Pulldown-Menüs haben den Sinn, daß die Anzeige von Hauptinhalten übersichtlicher gestaltet  werden kann. Unterpunkte können zunächst verborgen bleiben. Erst beim Anwählen eines Hauptpunktes erscheinen die Einzelheiten.
Es gibt mehrere Möglichkeiten, Pulldown-Menüs zu gestalten:

Grafisches Pulldown-Menü

Etwas undeutliche Bezeichnung, die durchaus mißverstanden werden darf. Gemeint ist, daß man das Pulldown-Menü durch Wechsel geeignet gestalteter Bilder realisieren kann. Auf den Bildern können Texte, aber natürlich auch Grafiken die Links anbieten. Ausgewertet wird das Menüfenster als "sensitive Grafik".
Dieses Menü hat durchaus einen Nachteil: Der Platz für das Menü ist von Anfang an reserviert. Vom "Pulldown" kann, so gesehen, keine Rede sein.
 
Eintrag im Head-Teil
<script language="JavaScript">
   function menue_runter() {document.menu.src="bilder/m_voll.gif";}
   function menue_hoch() {document.menu.src="bilder/m_teil.gif";}
</script>
Richtigen Startzustand im <body>-Tag sichern:
<body  onLoad="menue_hoch()">
Der Menü-Aufruf selbst:
<a href="xx.htm" onMouseOver="menue_runter()" onMouseOut="menue_hoch()">
<img src="bilder/m_voll.gif" alt="Das Kursangebot" name="menu" BORDER=0 usemap="#men_feld" height=125 width=100></a>
<map name="men_feld">
   <area shape=rect coords="0,25,100,50" href="../html/home.htm target="_top" alt="zum HTML-Kurs">
   <area shape=rect coords="0,50,100,75" href="../css/home.htm" target="_top" alt="zum CSS-Kurs">
   <area shape=rect coords="0,75,100,100" href="http://www.tfh-wildau.de/rhirte/informatik/layer/start.htm" target="_top" alt="zur layer-Übersicht">
   <area shape=rect coords="0,100,100,125" href="home.htm" target="_top" alt="zum JavaScript-Kurs">
</map>
Das Kursangebotzum HTML-Kurszum CSS-Kurszur layer-Übersichtzum JavaScript-Kurs

Dieses Menü nutzt für den Bildwechsel das Event "onMouseOver", das mittlerweile meistens funktioniert. Was man auslöste war hier der Bildwechsel, was den Nachteil hatte, daß das Menü insgesamt im Seitentext erscheint.
Eine reizvolle Alternative ist, nur das Überschriftenbild erscheinen zu lassen, die Menüeinträge aber über dem Folgetext anzubieten.


Pulldown-Menü, das über dem Text öffnet.

Benötigt wird zunächst ein Überschriftenbild oder vielleicht auch nur ein Textlink. Wenn das oder der mit der Maus überfahren wird, oder wenn sie geklickt werden, soll sich unterhalb dieser Überschrift, aber über dem Folgetext der Menübereich öffnen.

Was man braucht, sind Container, etwa "div"s, die man erst dann erscheinen läßt, wenn sie gebraucht werden.


Listenfeld als Pulldown-Menü

Das HTML-Listenfeld läßt sich leicht zum Menü ausbauen. Der Nachteil ist sein Aussehen. Der Vorteil ist echter Gewinn an Übersichtlichkeit, denn dieses Menü liefert echtes "Pulldown-Feeling".
Ein Beispiel:
 
Die Javascript-Funktion im Head:
<script language=JavaScript>
   function meinMenue()
   {
      nummer=window.document.menufeld.menu.selectedIndex;
      if(nummer>0){
         seite=window.document.menufeld.menu.options[nummer].value;
         self.location.href=seite;
      }
   }
</script>
Das Menü selbst:
<form name="menufeld">
   <select name="menu" onChange="meinMenue()">
      <option>Überschrift
      <option value="erste.htm">Erste Seite
      <option value="zweite.htm">Zweite Seite
      <option value="dritte.htm">Dritte Seite 
      <option value="vierte.htm">Vierte Seite
      <option value="fünfte.htm">Fünfte Seite
   </select> 
</form>

Erläuterung zum Code:
Der Zugriff auf den gewählten Listeneintrag sieht sehr umständlich aus. (Er ist es!) Aber, es gibt einen Grund. Es muß nämlich nacheinander die ganze Objekthierarchie benannt werden. Die erste Funktionszeile erfragt den gewählten Index von option (der mit 0 beginnt), indem außer Fenster und Dokument auch Formularname und Name des Formularelements genannt werden.
Für die Benennung gibt es zwei Optionen. Für Formular und Formularelement habe ich hier Namen vergeben und diese beim Aufruf verwendet. Auch für option hätte ich einen Namen (genau einen für alle!) vergeben können. Statt der Namen sind immer die vom Browser geführten Arrays forms[], elements[] ansprechbar. Allerdings muß man dann bei der Arbeit an einer größeren Seite aufpassen, daß man nicht durch nachträgliche Änderungen die Zählung der benötigten Elemente verschiebt.
Anstelle von hier ".menufeld.menu" können also die jeweils vom Autor gewählten Namen oder aber ".forms[0].elements[0]" eingesetzt werden, wenn das Menü im ersten Formular der Seite als erstes Tabellenelement angeordnet ist.
Wenn Sie die Links anwählen, gibt es hier Fehlermeldungen. Mit Absicht, weil Sie ja diese Seite sicher nicht verlassen wollen! Die Fehlermeldungen, die man studieren sollte, beweisen, daß die Links funktionieren. Es werden die Seiten gesucht, die im Quelltext genannt sind, aber natürlich (hier) nicht existieren.


Frei gestaltetes Pulldown-Menü

Zuerst die gute Nachricht: Man kann freier gestalten, wenn man nicht das Listenfeld wählt. Eine Realisierungsmöglichkeit, die Javascript zum Verbergen bzw. Sichtbarmachen normaler Links nutzt, sei hier vorgestellt. JavaScript selbst kann -glaube ich- nichts verbergen. Dazu bieten sich aber styles an. Was das ist, kann man hier nachlesen.
Jetzt die schlechte Nachricht: Was hier folgt, funktioniert nicht im Netscape-Browser! Die Gründe sind: Netscape wertet das onClick-Ereignis nur im <a>-Tag und einigen Tabellenelementen aus. Dies ließe sich noch umschiffen, indem man für die Menü-Überschriften das <a>-Tag nutzt, es gleichzeitig mit name="xyz" zur Marke und mit href="#xyz" zum Link auf sich selbst macht. Dann wird onClick ohne weitere Folgen weitergemeldet. Aber es nützt nichts. Denn ein zweites, ernsteres Hindernis besteht darin, daß der Zugriff auf das Attribut class nur mit Hilfe des Unterobjektes all von document möglich ist. Und dieses kennt man bei Netscape nicht!
Im head-Teil anzulegen:
<style type="text/css">
   .weg a{display:none}
   .da a{display:normal}
</style>
<script language=JavaScript>
   function roll(num)
   {
      if(document.all[num].className=="weg")document.all[num].className="da";
      else document.all[num].className="weg";
   }
</script>
Im Dokument selbst steht:
<span class="weg" id="m1" onClick="roll('m1');" >
   <b>Überschrift 1</b><br>
   <a href="1.htm" >Eintrag 1.1<br></a>
   <a href="2.htm" >Eintrag 1.2<br></a>
   <a href="3.htm" >Eintrag 1.3<br></a>
   <a href="4.htm" >Eintrag 1.4<br></a>
</span>
<span class="weg"  id="m2" onClick="roll('m2');" >
   <b>Überschrift 2</b><br>
   <a href="5.htm" >Eintrag 2.1</a><br>
   <a href="6.htm" >Eintrag 2.2</a><br>
</span>

Hier beginnt mein Probemenü:

Überschrift 1
Eintrag 1.1
Eintrag 1.2
Eintrag 1.3
Eintrag 1.4
Überschrift 2
Eintrag 2.1
Eintrag 2.2


Platzsparendes Pulldownmenü

Drei Nachrichten, zuerst die zwei guten: Erstens, man kann "echte" Pulldownmenüs erzeugen, also solche, die vorab keinen Platz reservieren; zweitens und noch viel besser, sie funktionieren in allen Browsern, die JavaScript können (und wollen). Jetzt die schlimme Nachricht, es geht nur mit Frames, ein solches Menü muß auf einem eigenen Navigationsfenster stehen. Wer ohnehin mit einem Navigationsframe arbeiten will, darf sich freuen.
Die zu realisierende Idee besteht darin, daß auf ein geeignetes Ereignis (ein Event) hin der gesamte Inhalt des Navigationsframes neu geschrieben wird.
Ich stelle hier die Technik kurz vor. Wer sie in Aktion sehen möchte, besuche meinen Visual-Basic-Kurs, der diese Technik nutzt.
Das an sich völlig normale Frameset erhält im head-Bereich die erforderlichen Variablen und Steuerfunktionen.
So etwa könnte das Frameset aussehen:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
<HTML>
    <HEAD>
       <TITLE>
         Frameset
      </TITLE>
<SCRIPT language="JavaScript" type="text/javascript">
<!--
 
// Hier kommen die Variablendefinitionen und Funktionen rein!
 
//-->
</SCRIPT>
    </HEAD>
    <FRAMESET>
       <FRAME name="links" src="index.htm">
      <FRAME name="rechts" src="startseite.htm">
      <NOFRAMES>
         <BODY>
         </BODY>
      </NOFRAMES>
   </FRAMESET>
</HTML>

Da der gesamte Seitencode der Steuerseite immer neu geschrieben werden soll, ist es ratsam, die unveränderlichen wie die veränderlichen Teile des Codes Variablen zuzuweisen, die einmal geladen, solange zur Verfügung stehen, wie das Frameset geladen bleibt. Je nach Anforderung wird der Seitentext zusammengebastelt.
Damit die Sache verständlich wird, eine ganz umständliche Erklärung: Der Seitentext setzt sich zusammen aus: Kopfttext (kopf) plus Texte für geschlossene Menüpunkte (m_zu[i]) + Text für geöffnetes Teilmenü (m_auf[i]) plus Text für restliche geschlossene Menüpunkte (m_zu[i]) + Text für Seitenenende (fuss). Die folgende Tabelle zeigt eine Beispiel für mögliche Inhalte dieser Variablen.
Die haben es in sich. Denn in den Variablen m_zu[i] sind die Aufrufe der später folgenden Funktion schreib(nummmer) versteckt, die das Menü verändern wird.
var kopf="<\/HEAD> <BODY><B>Dies ist die Überschift<\/B><HR>";
 
var m_zu=new Array(10);
m_zu[1]="<B><A href='javascript:parent.schreib(1)'>Einleitung<\/A><\/B><BR>";
m_zu[2]="...";
...
m_zu[10]="...";
 
var m_auf=new Array(10);
m_auf[1]= "<A href='erste.htm' target='rechts'>Erster Eintrag<\/A> <BR><A href='zweiter.htm' target='rechts'>Zweiter Eintrag<\/A> <br> <A href='dritter.htm' target='rechts'>Dritter Eintrag<\/A>";
m_auf[2]="...";
...
m_auf[10]="...";
 
var fuss="<HR><SPAN class=cop>© Rolf Hirte<BR>zuletzt bearbeitet: 05.09.2000<\/SPAN>";
Ebenfalls in den head-Teil des Framesets kommen die Funktionen, die die Arbeit machen. Das ist einmal das Zusammenstellen des Seitentextes. Die Variable x gibt die Nummer des geöffneten Menüpunktes an. Null bedeutet, daß alle Teilmenüs geschlossen sind
function baum(x)
{
   men=kopf;
   if(x==0)
      for(i=1;i<=14;i++)men+=m_zu[i];
   else
   {
      for(i=1;i<=x;i++)men+=m_zu[i];
      men+=m_auf[x];
      for(i=x+1;i<=14;i++)men+=m_zu[i];
   }
   return men+fuss;
}

Nun fehlt noch der eigentliche Aufruf und Schreibakt, der als "Knips"-Funktion realisiert wird. Auf Mausklick wird ein geschlossener Menüpunkt geöffnet, ein geöffneter geschlossen. In jedem Falle folgt auf das "Event" das Neuschreiben der Steuerseite, deren Startzustand in "index.htm" steht und deren aktueller Text über baum(knips) erzeugt wird.
function schreib(x)
{
   if (knips==x)knips=0;
   else knips=x;
   links.document.write(baum(knips));
   links.document.close()
}

Nachdem diese Vorbereitungen getroffen worden sind, ist schon fast alles passiert. Fast. Es fehlt die Seite "index.htm" mit der es mal irgendwann losgeht. Sie könnte etwa so aussehen:
<HTML>
   <HEAD>
       <TITLE></TITLE>
   </HEAD>
   <body>
<SCRIPT LANGUAGE=JavaScript>
<!--
document.write(parent.baum(0));
// -->
</SCRIPT>
    </BODY>
</HTML>
So, das war's. Etwas umständlich aber lohnend.