Google Chrome または Safari を使用される事を強くお薦めしますw
他のブラウザでは Javascript の処理が重いです(汗)


2010/09/01

イベントリスナーについてちょっとだけ考える

なんか読者になってる人いるしw こんなブログのどこ読むねんwww


イベントリスナーについて考えるっつったって、要するに IE にどう対処しましょうかってことなんですがw

簡単にまとめると違いはこう。

ブラウザメソッドキャプチャの可否リスナでのイベント取得方法リスナでのthisの値
IEattachEvent不可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 件のコメント:

コメントを投稿