JavaScript のブラウザごとのイベントハンドラ登録の違いを吸収する [JavaScript]
◆JavaScript のブラウザごとのイベントハンドラ登録の違いを吸収する
さてさて。
ユーザーエージェント(ブラウザ)ごとに、イベントハンドラの登録の仕方が違うのは、attachEvent メソッドと addEventListener メソッドのエントリーで書きました。
でも、いちいちユーザーエージェントの違いを判別して、attachEvent メソッドと addEventListener メソッドを使い分けるのは、面倒ですよね。
てことで、この違いを簡単に吸収するメソッドを自作します。
これは、前回のエントリー「【遊び】逃げるボタン」で使っているものです。
その実装例は、こちら。
function addEvent(event, function, capture) {
if (this.addEventListener)
this.addEventListener(event, function, capture);
else if (this.attachEvent)
this.attachEvent('on' + event, function);
else
errorEnvironment();
}
Object.prototype.addEvent = addEvent;
HTMLDocument.prototype.addEvent = addEvent;
Element.prototype.addEvent = addEvent;
prototype で組み込みクラスを拡張できるのは、JavaScript ならではの利点。
これを使わない手はねえぜ!
このメソッドは、 this に attachEvent メソッドがあれば attachEvent メソッドを、addEventListener メソッドがあれば addEventListener メソッドを使います。
第一引数はイベント名文字列 event(プレフィックス 'on' を使わない)、第二引数は登録したいイベントハンドラ メソッド function を指定します。
第三引数 capture はキャプチャーで、Firefox、Safari、Google Chrome でしか効力を発揮しませんが、まあよしとしておきましょう。
prototype がいっぱいありますが、これはすべて Internet Explorer のせい。
Object.prototype.addEvent = addEvent; は、Firefox、Safari、Google Chrome、Opera の4種類のブラウザで、Window クラス(DOMWindow クラス)、HTMLDocument クラス、Element クラスのすべてを網羅できます。
ところが、Internet Explorer では、Window クラスしか拡張できないんですね(IE8 で確認)。
これは、理由が2つあって、Internet Explorer 8 が各々のクラスの中でイベントを制御していることと、Internet Explorer 8 が Object prototype 拡張を無視しているからです。
Internet Explorer 8 の拡張は、単に window スコープで function を準備しているから・・・・・・という理由だけです。
仕方がないので、Internet Explorer のためだけに、 HTMLDocument.prototype.addEvent = addEvent; と、Element.prototype.addEvent = addEvent; を準備してます。
これで、主要なブラウザすべてで、addEvent メソッドだけで、Window クラス(DOMWindow クラス)、HTMLDocument クラス、Element クラスのイベントハンドラを登録できるようになります。
この手法は、「【遊び】逃げるボタン」 のエントリーでも使ってます。
あ、ただし、このソースは、IE6 以前(IE6 を含む)では動かないかもしれません(一部の組み込みクラスしか prototype 拡張に対応してなかった記憶があります)。
ちなみに、上記の実装例にある errorEnvironment メソッドは、これらで対応できないユーザーエージェント(ブラウザ)のときに、エラーを示す alert を出力する関数です。
function errorEnvironment() {
alert('ご使用の環境は、このスクリプトではサポートされません。');
}
この addEvent メソッドを使った例を掲載しておきます。
<!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>addEvent</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;
// ウィンドウ ロード イベントハンドラ
function onWindowLoad(evt) {
var elm;
elm = document.getElementById('Button1');
elm.addEvent('click', function () { alert('ボタンが押されました。'); });
alert('window のロードが完了しました。');
}
// 唯一の初期化
window.addEvent('load', onWindowLoad, true);
//]]
</script>
</head>
<body>
<input id="Button1" type="button" value="button" />
</body>
</html>
このソースをメモ帳にでも貼り付けて、ファイル名を "index.html" とでもして保存し、このファイルを各ブラウザにドロップしてもらえればわかりますが、Internet Explorer、Firefox、Safari、Google Chrome、Opera、どのブラウザでも同じ挙動をします(キャプチャーを除く)。
window のロードが完了すると 'window のロードが完了しました。' というダイアログ ボックスが出て、ボタンを押すと 'ボタンが押されました。' というダイアログ ボックスが表示されます。
ただ、このソースは「お行儀」 がよくありません・・・・・・動的に登録したイベントハンドラを、detachEvent なり removeEventListener なりで解放してやるべきなんですが、それをやっていないんですね。
別にわざわざ開放しなくても、対象のインスタンスが消失すれば自動的にいなくなるんでしょうが、それは「気持ち悪い」ってもんです。
というわけで、次回はこの addEvent の要領で、ユーザーエージェントの差異を意識せずにイベントハンドラを開放する方法を実装します。
Javaは興味ありますw
by One-for-you (2010-12-19 00:37)
Java と JavaScript はまったく別物なので、気をつけた方がいいですよ。
このふたつを混同すると、エンジニアと話がかみ合わなくなります。
by みみちゃん (2010-12-19 11:24)
素人は、Javaは言語でJavaScriptはネスケ(でしたっけ?)のブラウジング言語ってな感じで理解してるけど、思いっきり外して外してるかもしれません
by One-for-you (2010-12-21 22:13)