Jagged: Werden Event-Handler vererbt? Und wenn ja, wie...

High,

bei mir zeigt sich folgendes Problem:

  
  .GruppeA {position:fixed;top:9ex;left:0px;bottom:0px;width:64px}  
  .GruppeB {position:fixed;top:9ex;left:0px;width:256px;visibility:hidden}  

  
  <div class="GruppeA" onmouseout="phidemenu()" onclick="showGrpB()">  
    <img src="gfx/loftbar.png"  
         hspace=0 border=0 width="64px" height="226px"/>  
    <!-- noch ein Image, das sich bis zum Boden fortsetzt... -->  
  </div>  
  <div class="GruppeB" id="grpB" onmouseout="hideGrpB()">  
    <img src="gfx/leftbar.png"  
         hspace=0 border=0 width="256px" height="320px" />  
  </div>  

  
  function showGrpB()  
  {  
    document.getElementById("grpB").style.visibility="visible";  
  }  
  function phideGrpB()  
  {  
    return true;  
  }  
  function hideGrpB()  
  {  
    document.getElementById("grpB").style.visibility="hidden";  
  }  

Also, auf Hochdeutsch: Ein Click auf GruppeA soll GruppeB aufpoppen lassen. Das funktioniert auch. Allerdings verschwindet GruppeB nicht erst, wenn die Maus GruppeB verlässt, sondern bereits, wenn sie GruppeA verlässt, und zwar ungeachtet dessen, ob sie dann inner- oder unterhalb von GruppeB ist.

GruppeA scheint irngwie den Eventhandler für onmouseout von GruppeB zu übernehmen.

Die Idee von phideGrpB() ('p' wie pseudo) ist, dass GruppeA vielleicht nicht den onmouseout-Event triggert, der GruppeB wieder schließt, wenn sie einen eigenen, expliziten Eventhandler zugewiesen bekommt. Funktioniert aber nicht.

Über Event-Bubbles etc. habe ich schon gelesen, aber das hier ist wohl etwas anderes, oder? Hat da jemand eine Idee?

Gruß und Danke im Voraus,
Jagged

  1. Hi,

    Über Event-Bubbles etc. habe ich schon gelesen, aber das hier ist wohl etwas anderes, oder?

    Ja.
    mouseover/-out feuern auch dann, wenn du Nachfahrenelemente des Elementes überfährst.

    Du musst also das target des Events abfragen, und darauf passend reagieren.
    Framworks wie jQuery bieten dafür übrigens eigene Events namens mouserenter/mouseleave an - die reagieren so, wie man das vielleicht erst mal von den oben genannten erwarten würde.

    MfG ChrisB

    --
    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
    1. Du musst also das target des Events abfragen, und darauf passend reagieren.
      Framworks wie jQuery bieten dafür übrigens eigene Events namens [...]

        
        function hidemenu()  
        {  
          var trgr=window.event.target; /* has triggered the event */  
          var ntype=trgr.nodeName;  
          while (ntype!="DIV" & ntype!="BODY") /* search above "body" */  
          {                                    /* is quite pointless  */  
            trgr=trgr.parentNode;  
            ntype=trgr.nodeName;  
          }  
          if (ntype="DIV")  
          {  
            if (trgr.getAttribute("id")=="grpB")  
              document.getElementById("grpB").style.visibility="hidden";  
            else  
              window.event.stopPropagate();  
          }  
        }  
      
      

      Nach einiger Pfriemelei ist obiges herausgekommen. Schon beim Rumtesten mit parentNode und Co. wurde ersichtlich, dass der Handler zweimal aufgerufen wird, wenn GruppeB sichtbar ist.

      Deshalb habe ich mal das stopPropagate() eingebunden, das ich während der Event-Bubbles-Recherche aufgeschnappt habe... Der Effekt bleibt der gleiche. Was übersehe ich da?

      Nochmal danke :-)

      PS: dass ich mir den getEleme*-Aufruf hier sparen könnte, ist mir schon klar ;-)

      1. function hidemenu()
          {
            var trgr=window.event.target; /* has triggered the event */

        Browserübergreifender Zugriff auf das Event-Objekt

        var ntype=trgr.nodeName;
            while (ntype!="DIV" & ntype!="BODY") /* search above "body" */
            {                                    /* is quite pointless  */
              trgr=trgr.parentNode;
              ntype=trgr.nodeName;
            }
            if (ntype="DIV")
            {
              if (trgr.getAttribute("id")=="grpB")

        Du suchst das nächsthöher liegende div-Element und schaust, ob dieses eine ID »grpB« hat. Gut, das ist möglich. Das Beispiel, was ich dir gezeigt habe, verwendet übrigens die Funktion contains(), welche von manchen Browsern bereits unterstützt wird und in anderen einfach nachgerüstet werden kann.

        window.event.stopPropagate();

        Bubbling browserübergreifend verhindern

        Mathias

        1. Du suchst das nächsthöher liegende div-Element und schaust, ob dieses eine ID »grpB« hat. Gut, das ist möglich. Das Beispiel, was ich dir gezeigt habe, verwendet übrigens die Funktion contains(), welche von manchen Browsern bereits unterstützt wird und in anderen einfach nachgerüstet werden kann.

          Sorry, dass ich schon dabei war, meine eigene Lösung zu basteln, als du deine gepostet hast :-) Finde ich schon interessant, aber da stehen Sachen drin, die mir noch nie über den Weg gelaufen sind (toElement gibt's in SelfHTML 8.1.2 noch nicht)...

          Also mal eine Frage zwischendrin: Wo findet man denn eine "aktuelle" Referenz zu JavaScript und den damit erreichbaren Objekten/Properties? (Hab schon auf w3.org geguckt, aber kann ja nicht alles gleichzeitig lesen...)

          Zu deiner Lösung: bin mir nicht sicher, ob das zu meinem Dingsbums passt. Es ist so: GruppeA wird geklickt, dann geht GruppeB auf. GruppeB verdeckt den oberen Teil von GruppeA. Und solange GruppeA verdeckt ist...

          warte mal... na, erstmal: solange GruppeA verdeckt, also GruppeB sichtbar ist, interessieren nur die Events in GruppeB...

          nun zurück zum "warte mal..." Vielleicht sollte ich einfach GruppeA auf "visibility:hidden" schalten, während GruppeB sichtbar ist... mal testen...

          Nee, geht auch nicht... und wenn ich GruppeA dann nicht wieder sichtbar mache, generiert sie keine onclick-Events mehr, aber der onmouseout geht noch durch... Das ist total schräg...

          window.event.stopPropagate();

          Bubbling browserübergreifend verhindern

          War ja nur ein Versuch, aber danke für jeden Tipp :-)

          Die Sache mit den logging-Paragraphen ist übrigens echt sinnvoll... man lernt nie aus...

          1. Sorry, dass ich schon dabei war, meine eigene Lösung zu basteln, als du deine gepostet hast :-) Finde ich schon interessant, aber da stehen Sachen drin, die mir noch nie über den Weg gelaufen sind (toElement gibt's in SelfHTML 8.1.2 noch nicht)...

            SELFHTML ist inhaltlich 10 Jahre alt. Besonders für Event-Handling ist es nicht als Referenz geeignet.

            Also mal eine Frage zwischendrin: Wo findet man denn eine "aktuelle" Referenz zu JavaScript und den damit erreichbaren Objekten/Properties? (Hab schon auf w3.org geguckt, aber kann ja nicht alles gleichzeitig lesen...)

            MDN und MSDN. Quirksmode. Aber auch die W3C-Standards sind interessant, in dem Fall DOM 2 Events bzw. DOM 3 Events.

            toElement ist übrigens nur eine ältere Microsoft-proprietäre Eigenschaft (IE 4-8), der Standard definiert relatedTarget, welches mein Script ja auch als erstes nutzt, sofern es vorhanden ist.

            Die Sache mit den logging-Paragraphen ist übrigens echt sinnvoll... man lernt nie aus...

            Debug-Ausgaben sind mit console.log usw. einfach möglich.

            Mathias

        2. Browserübergreifender Zugriff auf das Event-Objekt

            
            function hidemenu(event)  
            {  
              if (!event) event=window.event;  
              var trgr=event.target; /* has triggered the event */  
              var ntype=trgr.nodeName;  
          
          

          In der hier letzten angezeigten Zeile wird mir von FF (3.6 + 6.0) angezeigt, 'event' sei nicht definiert, Opera sagt dazu gar nichts (überhaupt keine Meldung in der Fehlerkonsole), aber das zweite DIV geht dann auch nicht mehr zu...

          Also, irngwie finde ich mittlerweile lächerlich... Möglicherweise stelle ich mich ja selbst so ungeschickt (oder blöd) an... aber wo liegt dann mein Fehler?

          Ich meine, dass alle drei Browser (hab sogar noch mehr probiert, aber ohne Fehlerkonsole) den gleichen Fehler haben, ist ja wohl unwahrscheinlich... aber woran liegt das jetzt?

          1. Hi,

            function hidemenu(event)
              {
                if (!event) event=window.event;
                var trgr=event.target; /* has triggered the event */
                var ntype=trgr.nodeName;

            
            >   
            > In der hier letzten angezeigten Zeile wird mir von FF (3.6 + 6.0) angezeigt, 'event' sei nicht definiert  
              
            Nicht eher in der vorletzten?  
              
            Wie hast du die Funktion denn „als Eventhandler gesetzt“?  
            Wenn du das über ein Attribut im HTML gemacht hast,  
            `<div onclick="hidemenu()">...`{:.language-html}  
            dann „fehlt“ der event-Parameter jetzt natürlich.  
              
            Der wird nur dann automatisch als erster Parameter übergeben, wenn du den Eventhandler über JavaScript setzt.  
            <http://molily.de/js/event-handling-grundlagen.html#traditionelles-event-handling>  
              
            MfG ChrisB  
              
            
            -- 
            RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
            
            1. Nicht eher in der vorletzten?

              Ja, in der vorletzten :-)

              Der wird nur dann automatisch als erster Parameter übergeben, wenn du den Eventhandler über JavaScript setzt.

              Ja, habe ich mittlerweile per Javascript gesetzt... um ihn erst dann zu aktivieren, wenn diese GruppeB eben sichtbar wird, also im onclick-Handler der GruppeA...

              Nützt aber alles nichts... :-/

              1. Okay, habe auf molily dann noch die Info gefunden, dass ich die Funktion ohne die Klammern angeben muss (ist irngwie auch logisch...)...

                Allerdings geht GruppeB immer noch schon zu, wenn der Bereich von GruppeA verlassen wird, obwohl die Debugausgabe als Trigger GruppeB identifiziert... Also, <b>DAS</b> ist nun echt schräg... die Maus ist definitiv noch <b>inner</b>halb der GruppeB, wie kann dann onmouseout getriggert werden?

                1. Hallo,

                  Allerdings geht GruppeB immer noch schon zu, wenn der Bereich von GruppeA verlassen wird, obwohl die Debugausgabe als Trigger GruppeB identifiziert... Also, <b>DAS</b> ist nun echt schräg... die Maus ist definitiv noch <b>inner</b>halb der GruppeB, wie kann dann onmouseout getriggert werden?

                  Kannst du mal bitte eine reduzierte Testseite online stellen?

                  Mathias

                  1. Kannst du mal bitte eine reduzierte Testseite online stellen?

                    Nette Idee, aber gerade bei einer Reduktion tritt das nicht auf. Dadurch bin ich aber letztenendes dahintergekommen, was schief läuft:

                    neben GruppeA und GruppeB habe ich noch einen weiteren <div> (sagen wir mal GruppeC), der mit "left:64px" positioniert ist und _nach_ GruppeB deklariert wird, also einen höheren Z-Index hat... (oder niedriger? ich weiß die Reihenfolge gerade nicht, aber eben einen, der GruppeC höher liegen lässt als GruppeB)...

                    Bewege ich die Maus also weiter nach rechts als "left:64px", übernimmt GruppeC die Kontrolle, und die Maus verschwindet _logisch_ aus GruppeB...

                    Es ist ätzend, aber so ist es nunmal... Und ja, eher ätzend als lächerlich, weil die Logik noch nachvollziehbar ist... Trotzdem brauche ich den Layer von GruppeC oberhalb von GruppeB... mal sehen, ob ich noch was transparentes, das sich mit GruppeB deckt, drüberlegen und dann da den Handler einhaken kann.

                    Naja, jedenfalls vielen Dank für eure Hilfe!

                    Gruß,
                    Jagged

  2. GruppeA scheint irngwie den Eventhandler für onmouseout von GruppeB zu übernehmen.

    Die Idee von phideGrpB() ('p' wie pseudo) ist, dass GruppeA vielleicht nicht den onmouseout-Event triggert, der GruppeB wieder schließt, wenn sie einen eigenen, expliziten Eventhandler zugewiesen bekommt. Funktioniert aber nicht.

    Im Prinzip würde das funktionieren, vorausgesetzt du verhinderst das Bubbling.

    Allerdings ist das etwas schlechter Stil, weil von hintern durch die Brust ins Auge. Sinnvoller ist es hier, beim Verarbeiten des mouseover-Events zu prüfen, wo er herkommt und ggf. wo die Maus hingeht – also ob diese wirklich das B-Menü verlässt. Das folgende Beispiel zeigt solche Abfragen:

    http://molily.de/temp/mouseenter-mouseleave.html

    Hier wird beim mouseout untersucht, ob das Element, zu dem es sich hinbewegt, im Menü selbst liegt oder außerhalb. Nur wenn es darin liegt, haben wir einen echten mouseleave.

    Über Event-Bubbles etc. habe ich schon gelesen, aber das hier ist wohl etwas anderes, oder?

    Wenn deine Menüs verschachtelt sind, dann passiert Event-Bubbling. Auch wenn dein Quelltext das nicht zeigt, deine Beschreibung weist darauf hin.

    Mathias