Kd-one: Probleme mit DHTML-Menü

Ich hab mir mühevoll ein DHTML menü geschrieben, funktioniert auch soweit ganz gut, solange ich nur eine Ebene öffne.
Sobald ich aber versuche, aus der ersten Ebene eine zweite zu öffnen, spielt da Script verrückt.

Zur Erklärung:

Das Script:

timer=false
function show_it(id)
{
if(window.opera || (document.getElementById && !document.all))
document.getElementById(id).style.visibility = 'visible';
else if(document.all)
document.all[id].style.visibility = 'visible';
else if(document.layers)
document.layers[id].visibility = 'show';
}
function hide_it(id)
{
if(window.opera || (document.getElementById && !document.all))
document.getElementById(id).style.visibility = 'hidden';
else if(document.all)
document.all[id].style.visibility = 'hidden';
else if(document.layers)
document.layers[id].visibility = 'hide';
}

Der Aufruf erfolgt so:

<a class="sub" id="l2" href="#" onMouseOver="clean1();window.clearTimeout(timer);show_it('divMenu1')"
onMouseOut="timer=window.setTimeout('hide_it('divMenu1')',100);" style="cursor:default;">    ALLGEMEIN<img border="0" src="/images/pix.gif" width="16" height="9" alt=""></a>

Damit wird die erste Ebene geöffnet, deren Layer folgenden Aufruf enthält:

<div id="divMenu1" style="visibility:hidden;"
onMouseOver="change('l2','sub2');change('w2','mOverO');window.clearTimeout(timer);show_it('divMenu1')"
onMouseOut="change('l2','sub');change('w2','mOutO');timer=window.setTimeout('hide_it('divMenu1')',100);"><?php include("includes/allgemein/menue.txt") ?></div>

Das "DIV" wird via CSS definiert.

die zweite Ebene wird genauso wie die erste geöffnet, geht auch, solange die Maus den ersten Layer nicht verläßt.
So sieht der Layer aus:

<div id="divMenu6" style="visibility:hidden;"
onMouseOver="window.clearTimeout(timer);show_it('divMenu6');show_it('divMenu4');change('w64','mOverO');"
onMouseOut="change('w64','mOutO');timer=window.setTimeout('hide_it('divMenu6')',100);timer=window.setTimeout('hide_it('divMenu4')',200);"><?php include("includes/javascript/popup/menue.txt") ?></div>

Beim onMouseOver-Event sollte für den geöffneten Layer und auch den Layer, von dem dieses Menü geöffnet wird, der Timeout abgebrochen werden, solange die Maus über Layer 2 ist.
Genau das funktioniert aber nicht. Die funktion change() wird korrekt ausgeführt(Hintergrundbildtausch), ebenso das Verbergen der beiden Layer zeitverzögert.
Der Timeout ist aus zwei Gründen nötig:
Erstens braucht man ein wenig Zeit, um mit der Maus zwischen den Layern zu wechseln und zweitens flackert das Menü in Mozilla ganz fürchterlich, wenn der Timeout fehlt.

Nun wird der Timeout beim onMouseOver im zweiten Layer nicht abgebrochen und ich weiß nicht, warum.
Kann einer von euch Cracks den Fehler finden?

Ach ja, der Link zum Problemkind:
<a href="http://faq.united-web.at/layout_1.php" target="_blank">Unter JAVASCRIPT/POPUP´S schauen!</a>
(Sicherheitshalber hab ich unten die URL zur Seite nochmal eingefügt, für den Fall, daß der Link hier nicht funktioniert. :-)) )

Ach ja, noch was:
Bei meiner letzten Frage erhielt ich die Lösung zu meinem Problem in einer Form, mit der ich absolut nichts anfangen konnte. Erst die Erklärung eines anderen bereitete mir die Information so auf, daß ich auch die Zusammenhänge und somit das Problem verstehen konnte.
Ich ersuche um ausreichend dokumentierte Antworten, ich bin Anfänger in Sachen JavaScript, mit Verweisen auf allgemeine Problemlösungen oder versteckten Hinwiesen auf Lösungsansätze kann ich recht wenig anfangen, da ich u.U. die Ansätze mit meinen derzeitigen Kenntnissen (noch) nicht verstehe. Also, macht euch bitte die Mühe und antwortet so, daß es auch ein Dummy versteht. :-)

Danke und Gruß

Kurt

  1. Hallo Kurt

    Ich hab mir mühevoll ein DHTML menü geschrieben, funktioniert auch soweit ganz gut, solange ich nur eine Ebene öffne.
    Sobald ich aber versuche, aus der ersten Ebene eine zweite zu öffnen, spielt da Script verrückt.

    für einen Anfaeger sieht das gar nicht übel aus. Dein Problem ist ein riesiges Timerproblem. Du überschreibst dir dauernd deine Timer.

    Der Aufruf erfolgt so:

    <a class="sub" id="l2" href="#" onMouseOver="clean1();window.clearTimeout(timer);show_it('divMenu1')"
    onMouseOut="timer=window.setTimeout('hide_it('divMenu1')',100);" style="cursor:default;">    ALLGEMEIN<img border="0" src="/images/pix.gif" width="16" height="9" alt=""></a>

    hier setzt du den Timer auf Menue 1

    <div id="divMenu1" style="visibility:hidden;"
    onMouseOver="change('l2','sub2');change('w2','mOverO');window.clearTimeout(timer);show_it('divMenu1')"
    onMouseOut="change('l2','sub');change('w2','mOutO');timer=window.setTimeout('hide_it('divMenu1')',100);"><?php include("includes/allgemein/menue.txt") ?></div>

    hier löscht du ihn wieder und setzt ihn wieder auf Menue 1

    <div id="divMenu4" style="visibility:hidden;"
    onMouseOver="change('l5','sub2');change('w5','mOverO');window.clearTimeout(timer);show_it('divMenu4')"
    onMouseOut="change('l5','sub');change('w5','mOutO');timer=window.setTimeout('hide_it('divMenu4')',100);">

    hier löschst du den Timer von Menue 1 und setzt ihn auf Menue 4. Soweit alles in Ordnung. Wissen muß man allerdings, dass ein mouse-Event auch feuert, wenn ein anderes Element betroffen ist. z.B. ein TD. Die bezeichnet man als Bubbling. Siehe auch http://selfhtml.teamone.de/dhtml/modelle/microsoft.htm#event_bubbling

    Dein Mouseover und Mouseout-Event im Div-Tag werden also auch dann wirkungsvoll, wenn eine Tabellenzelle oder Zeile verlassen wird. Du merkst nur nichts davon.

    In dieser Zeile

    <tr>
           <td class="form6" id="w64" onmouseover="change(this.id,'mOver')" onmouseout="change(this.id,'mOut')"><a class="sub" href="#" onMouseOver="window.clearTimeout(timer);show_it('divMenu6');" onMouseOut="timer=window.setTimeout('hide_it('divMenu6')',100);" style="cursor:default;">

    Du löschst den Timer auf Menue 4 und setzt ihn auf Menue 6. Danach wirken die mouseevent vom div und dein Timer von Menue 6 wird gelöscht und auf Menue 4 gesetzt. Möchtest du jedoch das Untermenue 6 erreichen, so muß auch dieser Timer gelöscht werden. Hier erfolgt zum ersten Mal ein unerwünschtes Überschreiben der Timer.

    <div id="divMenu6" style="visibility:hidden;"
    onMouseOver="window.clearTimeout(timer);show_it('divMenu6');show_it('divMenu4');change('w64','mOverO');"
    onMouseOut="change('w64','mOutO');timer=window.setTimeout('hide_it('divMenu6')',100);timer=window.setTimeout('hide_it('divMenu4')',200);"><?php include("includes/javascript/popup/menue.txt") ?></div>

    hier versuchst du beide Timer wieder anzumelden. Du löscht den Timer auf Menue 4 und blendest Menue 6 ein. Beim Mouseevent ordnest du dann dem Timer Menue 6 zu und überschreibst ihn sofort mit Menue 4

    Menue6 wird dadurch programmgemäß ausgeblendet, da keine Referenz auf das Timeout mehr besteht.

    Abhilfe vom Timerproblem: du mußt mehrere Timer mitschleppen und koordinieren, was viel Aufwand bereitet.

    Alternativ, so habe ich es neulich gelöst, überwachst du die Position des Mauszeigers und blendest in Abhängigkeit davon aus. :-)
    Gegenüber der Timerproblematik ist das ein Kinderspiel.

    Eine weitere Möglichkeit sind verschachtelte Divbereiche, was für den NN4 zwar wieder Ärger bereitet, aber deine gegenwärtige Variante funktioniert da sowieso nicht.

    (Sicherheitshalber hab ich unten die URL zur Seite nochmal eingefügt, für den Fall, daß der Link hier nicht funktioniert. :-)) )

    siehe FAQ: </faq/#Q-19>

    Ach ja, noch was:
    Ich ersuche um ausreichend dokumentierte Antworten, ich bin Anfänger in Sachen JavaScript, mit Verweisen auf allgemeine Problemlösungen oder versteckten Hinwiesen auf Lösungsansätze kann ich recht wenig anfangen, da ich u.U. die Ansätze mit meinen derzeitigen Kenntnissen (noch) nicht verstehe. Also, macht euch bitte die Mühe und antwortet so, daß es auch ein Dummy versteht. :-)

    Ich habe mich bemüht, allerdings ist das Thema verteufelt verzwickt und die Lösung auch. Ich hoffe, ich habe mich nicht zu sehr vertimert :-)

    Viele Grüße

    Antje

    1. Hallo Kurt

      Ich hab mir mühevoll ein DHTML menü geschrieben, funktioniert auch soweit ganz gut, solange ich nur eine Ebene öffne.
      Sobald ich aber versuche, aus der ersten Ebene eine zweite zu öffnen, spielt da Script verrückt.

      für einen Anfaeger sieht das gar nicht übel aus. Dein Problem ist ein riesiges Timerproblem. Du überschreibst dir dauernd deine Timer.

      Danke dir für das Kompliment und auch für deine wirklich genaue Ausführung. Dadurch habe ich die Problematik begriffen. ;-)

      hier löschst du den Timer von Menue 1 und setzt ihn auf Menue 4. Soweit alles in Ordnung. Wissen muß man allerdings, dass ein mouse-Event auch feuert, wenn ein anderes Element betroffen ist. z.B. ein TD. Die bezeichnet man als Bubbling. Siehe auch http://selfhtml.teamone.de/dhtml/modelle/microsoft.htm#event_bubbling

      Ja, soweit auch klar, diese Problematik hat sich ja ursprünglich ganz deutlich in Mozilla gezeigt, der als einziger bei jeder Mausbewegung das Menü flackern ließ. Deshalb bin ich ja auf die Lösung mit dem Timer verfallen.

      Dein Mouseover und Mouseout-Event im Div-Tag werden also auch dann wirkungsvoll, wenn eine Tabellenzelle oder Zeile verlassen wird. Du merkst nur nichts davon.

      In dieser Zeile

      <tr>
             <td class="form6" id="w64" onmouseover="change(this.id,'mOver')" onmouseout="change(this.id,'mOut')"><a class="sub" href="#" onMouseOver="window.clearTimeout(timer);show_it('divMenu6');" onMouseOut="timer=window.setTimeout('hide_it('divMenu6')',100);" style="cursor:default;">

      Du löschst den Timer auf Menue 4 und setzt ihn auf Menue 6. Danach wirken die mouseevent vom div und dein Timer von Menue 6 wird gelöscht und auf Menue 4 gesetzt. Möchtest du jedoch das Untermenue 6 erreichen, so muß auch dieser Timer gelöscht werden. Hier erfolgt zum ersten Mal ein unerwünschtes Überschreiben der Timer.

      Nun, ich habe versucht, das Problem so zu umgehen, daß ich einen zweiten Timer(timer2) für die zweite Ebene definiert habe. allerdings wird, je nach Position immer nur einer der beiden angesprochen. Habe ich vielleicht bei der Timerdefinition einen Fehler gemacht?
      So sieht´s im Moment aus:
      im Script:

      timer=false
      timer2=false
      function show_it(id)
      {...restliche Definition

      Der Aufruf in Menu4:

      <td class="form6" id="w64" onmouseover="change(this.id,'mOver')" onmouseout="change(this.id,'mOut')"><a class="sub" href="#" onMouseOver="window.clearTimeout(timer2);show_it('divMenu6');" onMouseOut="timer2=window.setTimeout('hide_it('divMenu6')',100);" style="cursor:default;">POPUP´S</a></td>

      Und nun die Definition im divMenu6:

      <div id="divMenu6" style="visibility:hidden;"
      onMouseOver="window.clearTimeout(timer,timer2);show_it('divMenu6');show_it('divMenu4');change('w64','mOverO');"
      onMouseOut="change('w64','mOutO');timer=window.setTimeout('hide_it('divMenu4')',200);timer2=window.setTimeout('hide_it('divMenu6')',100);"><?php include("includes/javascript/popup/menue.txt") ?></div>

      Wenn ich den Timeout wie oben beschrieben lösche, wird, wenn zuerst der timer angeführt ist, Menü6 ausgeblendet, wenn timer2 zuerst angeführt wird, wird Menü4 ausgeblendet und Menü6 bleibt stehen.
      In diesem Falle kommt es auch zum oben beschriebenen Feuern, das heißt, beim Verlassen einer Zelle wird immer wieder kurzfristig Menü4 eingeblendet und verschwindet aber wieder. Um das zu verhindern, habe ich eigentlich die Timermethode angewandt????
      Irgendwie werde ich den Verdacht nicht los, daß ich bei der Definition der beiden Timer einen entscheidenden Fehler gemacht habe.

      Alternativ, so habe ich es neulich gelöst, überwachst du die Position des Mauszeigers und blendest in Abhängigkeit davon aus. :-)
      Gegenüber der Timerproblematik ist das ein Kinderspiel.

      Ja, möglich, aber mit dieser Problematik habe ich mich eigentlich überhaupt noch nicht auseinandergesetzt und wüßte auf Anhieb auch nicht, wie ich das realisieren könnte.

      Eine weitere Möglichkeit sind verschachtelte Divbereiche, was für den NN4 zwar wieder Ärger bereitet, aber deine gegenwärtige Variante funktioniert da sowieso nicht.

      Das verstehe ich nun nicht ganz. Menü 4 ist ein DIV-Bereich, indem aber letztendlich nur zwei Punkte der 7 möglichen einen neuen Layer aufrufen sollten. Wie könnte eine solche Verschachtelung aussehen?

      siehe FAQ: </faq/#Q-19>

      Danke für den Tip, das wußte ich noch nicht. ;-)

      Also, hier nochmal: http://faq.united-web.at/layout_1.php

      Ich ersuche um ausreichend dokumentierte Antworten, ich bin Anfänger in Sachen JavaScript, mit Verweisen auf allgemeine Problemlösungen oder versteckten Hinwiesen auf Lösungsansätze kann ich recht wenig anfangen, da ich u.U. die Ansätze mit meinen derzeitigen Kenntnissen (noch) nicht verstehe. Also, macht euch bitte die Mühe und antwortet so, daß es auch ein Dummy versteht. :-)

      Ich habe mich bemüht, allerdings ist das Thema verteufelt verzwickt und die Lösung auch. Ich hoffe, ich habe mich nicht zu sehr vertimert :-)

      Nö, ich habe, glaub ich, sehr gut verstanden, was du sagen wolltest. Wären alle Antworten so gut dokumentiert und aufbereitet. :-)))
      Danke dir!

      Kurt

    2. Danke!

      Dank deiner ausführlichen Hilfe klappt nun das Ganze!

      http://faq.united-web.at/layout_1.php

      Nochmals vielen Dank!

      Aber du hast schon recht, Der Umfang ist nicht zu unterschätzen, das nächste, wo ich mich nach einer kleinen Erholungsphase ranwagen werde, ist, das Ganze zu vereinfachen. ;-)

      Liebe Grüße

      Kurt

      1. Hallo Kurt

        ausgezeichnet, sieht wirklich gut aus

        Aber du hast schon recht, Der Umfang ist nicht zu unterschätzen, das nächste, wo ich mich nach einer kleinen Erholungsphase ranwagen werde, ist, das Ganze zu vereinfachen. ;-)

        große anspruchsvolle Scripts lasse ich immer gern einige Wochen liegen. Danach ist man nicht so betriebsblind, wenn es an die Optimierung geht.

        Ansonsten geht mein Dank zurück. Es macht Spaß jemanden zu helfen, der um das Verstehen bemüht ist und dem nur auf die Sprünge geholfen werden muß.

        Viele Grüße

        Antje