SSブログ

JavaScript のブラウザごとのイベントハンドラ開放の違いを吸収する [JavaScript]

◆JavaScript のブラウザごとのイベントハンドラ開放の違いを吸収する

さてさて。

ユーザーエージェント(ブラウザ)ごとに、イベントハンドラの登録や開放の仕方が違うのは、以前のエントリーでも書きました。

前回のエントリーでは、イベントハンドラの登録である attachEvent メソッドと addEventListener メソッドの違いを簡単に吸収する処理の実装例を掲載しました。

今回は、イベントハンドラの開放である detachEvent メソッドと removeEventListener メソッドの違いを吸収します。

これは、前々回のエントリー「【遊び】逃げるボタン」で使っているものです。

その実装例は、こちら。

function removeEvent(evt, func, cap) {
    if (this.removeEventListener)
        this.removeEventListener(eventt, function, capture);
    else if (this.detachEvent)
        this.detachEvent('on' + event, function);
    else
        errorEnvironment();
}
Object.prototype.removeEvent = removeEvent;
HTMLDocument.prototype.removeEvent = removeEvent;
Element.prototype.removeEvent = removeEvent;

このメソッドは、 this に detachEvent メソッドがあれば detachEvent メソッドを、removeEventListener メソッドがあれば removeEventListener メソッドを使います。

考え方は、前回のエントリーで提示した、イベントハンドラの登録メソッド addEvent とまったく同じです。

第一引数はイベント名文字列 event(プレフィックス 'on' を使わない)、第二引数は開放したいイベントハンドラ メソッド function を指定します。

第三引数 capture はキャプチャーで、FirefoxSafariGoogle Chrome でしか効力を発揮しません。

prototype がいっぱいある理由や、errorEnvironment メソッドは、前回のエントリー同様ですので、ここでは割愛します。

これで、主要なブラウザすべてで、removeEvent メソッドだけで、Window クラス(DOMWindow クラス)、HTMLDocument クラス、Element クラスのイベントハンドラを開放できるようになります。

この removeEvent メソッドを使った例を掲載しておきます。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>removeEvent</title>
    <script type="text/javascript">
        //<![CDATA[

        // 環境エラー
        function errorEnvironment() {
            alert('ご使用の環境は、このスクリプトではサポートされません。');
        }

        // イベントを追加する addEvent
        function addEvent(evt, func, cap) {
            if (this.addEventListener)
                this.addEventListener(evt, func, cap);
            else if (this.attachEvent)
                this.attachEvent('on' + evt, func);
            else
                errorEnvironment();
        }
        Object.prototype.addEvent = addEvent;
        HTMLDocument.prototype.addEvent = addEvent;
        Element.prototype.addEvent = addEvent;

        // イベントを削除する removeEvent
        function removeEvent(evt, func, cap) {
            if (this.removeEventListener)
                this.removeEventListener(evt, func, cap);
            else if (this.detachEvent)
                this.detachEvent('on' + evt, func);
            else
                errorEnvironment();
        }
        Object.prototype.removeEvent = removeEvent;
        HTMLDocument.prototype.removeEvent = removeEvent;
        Element.prototype.removeEvent = removeEvent;


        // 小さい関数群
        function getWinText() { return document.getElementById('win'); }
        function getDocText() { return document.getElementById('doc'); }
        function getBtnText() { return document.getElementById('btn'); }
        function getButton(intNum) { return document.getElementById('Button' + String(intNum)); }

        // input text のクリア
        function onClearText(evt) {
            getWinText().value = '';
            getDocText().value = '';
            getBtnText().value = '';
        }

        // ウィンドウのクリック イベント
        function onWindowClick(evt) {
            getWinText().value = 'window がクリックされました。';
        }

        // ドキュメントのクリック イベント
        function onDocumentClick(evt) {
            getDocText().value = 'document がクリックされました。';
        }

        // ボタンのクリック イベント
        function onButtonClick(evt) {
            getBtnText().value = 'button がクリックされました。';
        }

        // イベントの登録状態
        var isAdded = false;

        // イベントの一括登録
        function addAllEvents(evt) {
            if (!window.isAdded) {
                window.addEvent('click', onWindowClick, false);
                document.addEvent('click', onDocumentClick, false);
                getButton(1).addEvent('click', onButtonClick, false);
            }
            window.isAdded = true;
            getButton(2).disabled = window.isAdded;
            getButton(3).disabled = (!window.isAdded);
            onClearText(null);
        }

        // イベントの一括解放
        function removeAllEvents(evt) {
            if (window.isAdded) {
                window.removeEvent('click', onWindowClick, false);
                document.removeEvent('click', onDocumentClick, false);
                getButton(1).removeEvent('click', onButtonClick, false);
            }
            window.isAdded = false;
            getButton(2).disabled = window.isAdded;
            getButton(3).disabled = (!window.isAdded);
            onClearText(null);
        }

        // ウィンドウのロード イベント
        function onWindowLoad(evt) {
            window.removeEvent('load', onWindowLoad, true);
            window.addEvent('unload', onWindowUnload, true);
            addAllEvents(null);
        }

        // ウィンドウのアンロード イベント
        function onWindowUnload(evt) {
            window.removeEvent('unload', onWindowUnload, true);
            removeAllEvents(null);
        }

        // 唯一の初期化
        window.addEvent('load', onWindowLoad, true);

        //]]
    </script>
</head>
<body>
    <div style="width:480px;border:solid 1px Black;">
        <input id="Button1" type="button" value="ボタン" />
        <input id="Button2" type="button" value="イベントの一括登録" onclick="addAllEvents(null);" />
        <input id="Button3" type="button" value="イベントの一括削除" onclick="removeAllEvents(null);" />
        <input id="Button4" type="button" value="テキストのクリア" onclick="onClearText(null);" />
        <table style="width:100%;">
            <tr style="width:100%;">
                <td style="width:30%;">window onclick</td>
                <td style="width:70%;"><input id="win" type="text" style="width:99%;" /></td>
            </tr>
            <tr>
                <td>document onclick</td>
                <td><input id="doc" type="text" value="" style="width:99%;" /></td>
            </tr>
            <tr>
                <td>button onclick</td>
                <td><input id="btn" type="text" value="" style="width:99%;" /></td>
            </tr>
        </table>
    </div>
</body>
</html>

かなり長いソースになっちゃいましたね;;;。

この HTML を起動すると、ブラウザにこんな画面が表示されます。

JavaScript_removeEvent_Sample.jpg

[ボタン] ボタンは、クリックイベントを捕まえるための button です。

[イベントの一括登録] ボタンは、window のクリックイベント、document のクリックイベント、button(Element サブクラス)のクリックイベントを一気に登録します。

[イベントの一括削除] ボタンは、window のクリックイベント、document のクリックイベント、button(Element サブクラス)のクリックイベントを一気に開放します。

[テキストのクリア] ボタンは、 下の3つのテキスト領域をクリアします。

window onclick は、window のクリックイベントが登録されているとき、window のクリックに反応して「window がクリックされました。」という文字列を表示します。

document onclick は、document のクリックイベントが登録されているとき、document のクリックに反応して「document がクリックされました。」という文字列を表示します。

button onclick は、button([ボタン])のクリックイベントが登録されているとき、button のクリックに反応して「button がクリックされました。」という文字列を表示します。

【注意】
Internet Explorer のみ、挙動が異なります。
どうやら、window のクリックイベントを捕まえられないようです。

とりあえず、これで、前回のエントリーと合わせて、ユーザーエージェント(ブラウザ)の違いを乗り越え、(ほぼ)共通のインターフェイスで、イベントハンドラの登録と開放ができるようになりました。

ところが・・・・・・。

イベントに関するブラウザ間の壁は、まだ残っています。

しかもその壁は、ひとつじゃありません。

イベントの登録や開放はメソッドが異なりましたが、プロパティが異なるものもあり、今回のようにブラウザによってはイベント自体が発生しない(IE8 window のクリックイベント)場合もあります。

次回以降は、まだ紐解いていない、イベントに関するブラウザ依存の事例をピックアップしていきます。


nice!(3)  コメント(2)  トラックバック(5) 
共通テーマ:パソコン・インターネット

nice! 3

コメント 2

One-for-you

白抜きのところを読んでると、演技を読んでるような漢字で、雰囲気が伝わります。 やっぱ、辞書が必要が、スクリプト用語辞典を買うか・・・そういう気持ちで、日中 or 日Espanolの辞書買ったけど、Body Languageで会話してる。

ソフトLanguageも、プロ領域に行かなければ、Body Language風にかけるような、おおきな勘違いしております、ですw
by One-for-you (2010-12-19 00:41) 

みみちゃん

そうそう・・・・・・このブログ、そもそもはリファレンスをそろえたいというのも目的のひとつなので、時間はかかるでしょうが、いずれは辞典代わりのものに育てたいです。
by みみちゃん (2010-12-19 11:26) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 5

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。