Laura: Capturing für IE simulieren - wie?

Hallo!

Ich bin gerade dabei, eine addEvent-Funktion zu schreiben, die Browser-Unabhängigkeit
gewährleisten soll - mit folgenden features:

1. alle Browser werden unterstützt (insbesondere IE und alte Browser, die weder
   addEventListener noch attachEvent kennen);
2. optional kann ein Array mit Parametern für den Handler übergeben werden;
3. mehrere Elemente können durch einen einzigen Funktionsaufruf zum listener werden;
4. event.stopPropagation, event.preventDefault und event.target funktionieren
   in den Handlern - in allen Browsern;
5. den capture-Modus auf true zu setzen klappt nicht nur in modernen Browsern.

1-4 habe ich bereits abgehandelt - 5 ist das große Problem.
Meine Idee war, wenn für capturing ein true übergeben
wird, bei den Browsern, die addEventListener nicht kennen, zunächst über eine
Hilfsfunktion einen Array zu erstellen, der die Reihenfolge festlegt, in der
die ganzen Handler vom target zum document feuern und diese dann manuell aufzurufen.
Nun gibt's da aber leider 2 große Hürden:

1. Die Reihenfolge hängt ja nicht nur vom capturing-Modus des target-Elements ab;
   das hieße wohl (wenn ich das capturing/bubbling-Konzept richtig verstanden habe,
   dass ich für jedes Element/Handler-Paar auch den cap-Modus irgendwo speichern muss.
   Das wäre nicht allzu schlimm, weil ich für die Browserkompatibilität sowieso
hash tables anlegen muss (z.B. elem.events[type][handler-id] = handler);
2. Dann kommt da aber noch die Möglichkeit hinzu, dass in einer (oder mehreren) der
   Handler-Funktionen ein event.stopPropagation(); notiert ist. Diese Information
   müsste also entweder als Parameter addEvent übergeben oder auf ganz
   umständliche sonstige Weise erhalten werden.

Hat sich hier jemand schon einmal die Mühe gemacht, für IE den capturing-Modus
zu simulieren oder weiß kennt einfach so einen Trick, den er aus seinem Ärmel hier
ins Forum schütteln kann?

Vielen lieben Dank,
Laura

  1. Hallo,

    ich will dich nicht demotivieren, aber grundsätzlich die Frage: Warum? Alle relevanten Browser kennen heutzutage addEventListener nativ und es existieren sehr ausgereifte Event-Handling-Bibliotheken, die die Normalisierung übernehmen.

    Capturing ist schön und praktisch, aber es wasserdicht nachzubauen, sodass es sich 100% wie die native Implementierung gemäß DOM Events verhält, ist meines Wissens unmöglich. Es gibt zuviele Fälle, die nicht abgedeckt werden können.

    Meine Idee war, wenn für capturing ein true übergeben
    wird, bei den Browsern, die addEventListener nicht kennen, zunächst über eine
    Hilfsfunktion einen Array zu erstellen, der die Reihenfolge festlegt, in der
    die ganzen Handler vom target zum document feuern und diese dann manuell aufzurufen.

    Im Prinzip ja, du holst dir alle Elternknoten des Elements bis zum document-Knoten und dispatchst dann die Handler nacheinander (vom document hinunter zum Element). Wenn dabei ein Handler stopPropagation oder stopImmediatePropagation aufruft, so brichst du die Verarbeitung ab.

    1. Die Reihenfolge hängt ja nicht nur vom capturing-Modus des target-Elements ab;
         das hieße wohl (wenn ich das capturing/bubbling-Konzept richtig verstanden habe,
         dass ich für jedes Element/Handler-Paar auch den cap-Modus irgendwo speichern muss.

    Ja, sicher. Es muss immer gespeichert werden, für welche Phase ein Handler registiert wurde.

    1. Dann kommt da aber noch die Möglichkeit hinzu, dass in einer (oder mehreren) der
         Handler-Funktionen ein event.stopPropagation(); notiert ist. Diese Information
         müsste also entweder als Parameter addEvent übergeben oder auf ganz
         umständliche sonstige Weise erhalten werden.

    Wieso umständlich?
    Zunächst einmal musst du stopPropagation ohnehin in Browsern erzeugen, die kein DOM Events kennen. Es ist also deine Funktion, die da aufgerufen wird. Die kann irgendeinen Flag setzen, den du nach dem Ausführen des Handlers abfragen kannst. wurde stopPropagation/stopImmediatePropagation aufgerufen, so brichst du ab.

    Hat sich hier jemand schon einmal die Mühe gemacht, für IE den capturing-Modus
    zu simulieren

    Nicht dass ich wüsste – zumindest wüsste ich nicht, dass es jemand geschafft hätte.

    Das Nachbauen von Capturing wird allein deshalb nicht korrekt funktionieren, weil man nicht immer Events in der Target-Phase überwacht. In aller Regel macht man (wissentlich oder nicht) vom Bubbling Gebrauch und registiert Handler an gemeinsamen Elternelementen. Hier beispielsweise ein Klick am a-Element:

    <a href="…" id="foo">Hallo <span>Welt</span></a>

    addEvent(document.getElementById('foo'), 'click', true) // Capturing = true

    Passiert der Event ursprünglich beim span-Element, so fange ich den Event erst in der Bubbling-Phase ab. Das heißt, die Target-Phase wurde schon durchlaufen, dabei möglicherweise Handler aufgerufen. Stünde zwischen span und a noch ein Elemente, würden auch dessen Handler aufgerufen. Jetzt kann ich nicht einfach, wenn der Event beim a ankommt, eine Capturing-Phase simulieren und plötzlich alle Capturing-Handler ausführen. Das würde nicht zum gewünschten Ergebnis führen. Sie könnten auch nicht wirksam stopPropagation aufrufen, schließlich wurden eventuell schon Target- und Bubbling-Handler ausgeführt.

    Deshalb nutzt man in der Praxis für jegliche Aufgaben der Event Delegation das Bubbling. Das funktioniert ziemlich gut. Natürlich gibt es einige Fälle, wo Capturing mehr Sinn ergeben würde, nur die kann man nicht browserübergreifend programmieren.

    Mathias

    1. Hey Mathias,

      ich will dich nicht demotivieren, aber grundsätzlich die Frage: Warum? Alle relevanten Browser kennen heutzutage addEventListener nativ und es existieren sehr ausgereifte Event-Handling-Bibliotheken, die die Normalisierung übernehmen.

      Ja, vielleicht sollte ich mir einfach eine kleine kompakte Event-Lib in meine eigene integrieren und mir den Aufwand ersparen...

      Vielen Dank für deine ausführliche Antwort :)
      Mein nächster Schritt: Nach Bibliotheken mit gutem Event-Handling stöbern.

      Liebe Grüße,
      Laura