イベントリスナーについて考えるっつったって、要するに IE にどう対処しましょうかってことなんですがw
簡単にまとめると違いはこう。
| ブラウザ | メソッド | キャプチャの可否 | リスナでのイベント取得方法 | リスナでのthisの値 | 
|---|---|---|---|---|
| IE | attachEvent | 不可 | window.eventを見る | windowを指す | 
| IE以外 | addEventListener | 可 | リスナの引数で渡される | イベントが発生した要素を指す | 
まず IE ではキャプチャフェーズでイベントを取得することができない(キャプチャ不可)なので、IE 以外のブラウザ用に addEventListener を使用する場合、第3引数を true にすることが有り得ません。
なのでクロスブラウザ用に自前の addEventListener 便利関数を作る場合にはここは false で決め打ちとなります。
function addEventListener(
             nodeTarget,
             strEventType,
             funcListener ) {
    // IE 以外
    if( nodeTarget.addEventListener )
        nodeTarget.addEventListener(
           strEventType,
           funcListener,
           false         // false 決め打ち
       );
    // IE
    else
        nodeTarget.attachEvent(
           'on' + strEventType,
           funcListener
       );
}
こんな感じ。とりあえずこれでリスナの登録はできるのだけれど、上記表を見てもらうと分かるようにまだ2つ問題があります。
・イベントオブジェクトの取得方法が違う
・thisの指す内容が違う
この2つが吸収できればリスナ側での場合分けが減ってかなりすっきりします。
なのでこんな風にしてみます。
function addEventListener(
             nodeTarget,
             strEventType,
             funcListener ) {
    // IE 以外
    if( nodeTarget.addEventListener )
        nodeTarget.addEventListener(
            strEventType,
            funcListener,
            false         // false 決め打ち
       );
    // IE
    else
        nodeTarget.attachEvent(
            'on' + strEventType,
            function() {
                return funcListener.call(
                    nodeTarget, window.event);
            }
        );
}
こうしておけばリスナ側で場合分けすることなく・リスナの引数→イベントオブジェクト
・this→イベントが発生した要素
に統一したコードが書けます。
もちろん IE のスカタンぶりは他にもいっぱいあるので、場合分けが全くいらなくなるわけではないですけどw
それでもこの方法はなんだか良さげに見えます。が。これだと
登録したリスナを削除できない
という問題がありますorz
登録しているのがクロージャなので削除のしようがありません。うーむ。
まあ自分が組むコードではリスナを削除するようなことはまずないんですけどね。
恐らく解決方法は
・配列にクロージャを追加して行き、remove時にはそこから探してきて削除する
ってことになると思います。その場合の問題点としては
・配列の添字は要素名とかイベント種別になるので、同じ要素同じイベントに対して複数のリスナを設定できない
がすぐに思い当たります。
ただし、
・そもそも IE では登録したリスナの実行順序が他のブラウザと異なる
ので、同じ要素同じイベントに対して複数のリスナを設定することがそもそも暴挙である気がしますw
ググると、自力で複数リスナの実行順序を他ブラウザと揃えようとしている方もいらっしゃるようです。完璧な解はないようですが。
Ajax(というか prototype.js)でもこのあたりは放置してるらしくw、私自身も先に書いたように登録したリスナを削除する必要性が今のところないので、この問題は放置しますwww
 
 
0 件のコメント:
コメントを投稿