アタッチイベントについて(Legacy Event)
アタッチイベントについて
■アタッチイベントについて
アタッチイベントは、 Internet Explorer 専用の仕様です。
Internet Explorer 11 以降では、廃止済みです。
通常の場合、標準化されたイベントの方を優先的に使用します。
■アタッチイベントについて
イベントの通知を、複数のリスナーが受け取る事ができます。
Internet Explorer 8 以前の環境で、複数のリスナーを登録したい場合に必要となります。
MSDN のリファレンスです。
http://msdn.microsoft.com/en-us/library/ie/jj853341.aspx (Legacy Platform Events)
■Opera(Presto 版) の場合
Opera(Presto 版) でも一部対応しています。
この場合、標準的な仕様で動作します。
Opera は、イベントリスナーに対応しているため、アタッチイベントを使う事は無いでしょう。
■イベントフェーズについて
大抵のイベントは、DOM ツリーと密接に関係しています。
■バブルズ(bubbles)について
大抵のイベントは、バブルズ(bubbles)に対応しています。
対象本人だけでなく、祖先にも通知されます。
バブルズに対応していないイベントは、対象本人にのみ通知されます。
■イベントフェーズについて
イベント通知の伝達順序として、以下の段階があります。
1.キャプチャ段階
2.ターゲット段階
3.バブリング段階
アタッチイベントの伝達順序は、イベント属性と同等です。
バブルズに対応しているイベントは、ターゲット段階 → バブリング段階 という順序で伝達されます。
バブルズに対応していないイベントは、ターゲット段階のみ実行されます。
1.キャプチャ段階
アタッチイベントには、キャプチャに相当する段階はありません。
3.ターゲット段階
ターゲット段階は、対象となるエレメント上で実行されます。
任意のリスナーにとって、自身にイベントが発生した事がわかります。
3.バブリング段階
バブリング段階では、子孫から Document に向かって順番に実行されます。
「ターゲットの直後」から「Document」まで実行されます。
アップしていく流れが、バブル(泡)となります。
任意のリスナーにとって、子孫にイベントが発生した事がわかります。
下の図であれば、1~4に登録したリスナーに相当します。
■イベントフェーズの流れを確認する
マウスボタンを押した時のイベントフェーズの流れを確認する
<html>
<body>
<div style="width:400px; height:300px; background:#fcc;">
<span style="font-size:32px;">あいうえお</span>
</div>
<script type="text/javascript">
<!--
// ------------------------------------------------------------
// DOM オブジェクトのすべての子孫を検索する関数
// ------------------------------------------------------------
function DomNodeFindAllDescendants(node,func){
function f(n){
var nodes = n.childNodes;
var i;
var num = nodes.length;
var a = new Array();
for(i=0;i < num;i++){ a[i] = nodes[i]; }
for(i=0;i < num;i++){
node = func(a[i]);
if(node){ return node; }
node = f(a[i]);
if(node){ return node; }
}
return null;
}
return f(node);
}
// アタッチイベントに対応している
if(window.attachEvent){
// ------------------------------------------------------------
// 要素にリスナーを登録する関数
// ------------------------------------------------------------
function ElementAttachEventMouseDown(current){
// アタッチイベントに対応しているか
if(!(current.attachEvent)) return;
// 要素にリスナーを登録
current.attachEvent("onmousedown" , function (e){
var target = e.srcElement;
console.log("カレント:" + current + "(" + current.nodeName + ")");
console.log("ターゲット:" + target + "(" + target.nodeName + ")");
console.log("---");
});
}
// ------------------------------------------------------------
// すべてのフェーズでリッスンを開始
// ------------------------------------------------------------
// ドキュメントにリスナーを登録
ElementAttachEventMouseDown(document);
// コールバック関数を使って、ドキュメントのすべての子孫を検索
DomNodeFindAllDescendants(document,function (node){
// ドキュメントの子孫にリスナーを登録
ElementAttachEventMouseDown(node);
// 検索を継続
return null;
});
}
//-->
</script>
</body>
</html>
EventObj クラスについて
■ EventObj クラスについて
EventObj オブジェクトは、イベント関連の情報を格納し、リスナーに渡すための入れ物です。
システム側からイベントが発行される場合、システムが、EventObj オブジェクトを生成します。
登録したコールバック関数の引数から、EventObj オブジェクトを受け取る事ができます。
EventObj クラスに派生はありません。
マウスやキーボード用の、様々なプロパティが混在しています。
■EventObj のプロパティについて
EventObj オブジェクトには、以下のプロパティがあります。(一部抜粋)
プロパティ名 | 型 | 説明 |
type | String | イベント名を取得する。(接頭の on は省略される) |
srcElement | Element | イベントの発生場所を意味する。ただし、エレメントではない場合 null。 |
returnValue | Boolean | リスナーから得られた戻り値情報を意味する。 false を指定すると、デフォルトの動作をキャンセルできる。 |
cancelBubble | Boolean | イベントの伝達(バブリング)を終了したい場合 true を指定する。 |
■ srcElement プロパティ
イベントの発生場所を取得するには、srcElement プロパティを使用します。
ただし、エレメントではない場合、null が得られます。
例えば Window オブジェクトにリスナーを登録した場合、null が得られるでしょう。
これは、DOM Event の Event.target プロパティに相当します。
■カレントターゲットを取得する
カレントターゲットを取得する方法はありません。
クロージャなどを利用して、カレントターゲット情報を保持しておきます。
これは、DOM Event の Event.currentTarget プロパティに相当します。
コールバック関数から、カレントターゲットを取得する
// アタッチイベントに対応している
if(element.attachEvent){
// ------------------------------------------------------------
// 匿名関数を即時実行する
// ------------------------------------------------------------
(function(){
// ------------------------------------------------------------
// ローカル変数
// ------------------------------------------------------------
// カレントターゲット
var current_target = document;
// ------------------------------------------------------------
// クリックすると実行されるイベント
// ------------------------------------------------------------
current_target.attachEvent("onclick" , function (e){
// 出力テスト
console.log(current_target);
});
})();
}
■デフォルトの動作をキャンセルする
イベントの種類によっては、キャンセルに対応している場合があります。
任意の動作が行われる直前に、イベントが発行されます。
リスナー側で、任意の動作をキャンセルするか選択する事ができます。
例えば、onclick や onkeypress イベントなどが対応しています。
■デフォルトの動作をキャンセルする
デフォルトの動作をキャンセルするには、コールバック関数内で、false 値を返します。
returnValue プロパティに、false をセットしても同等の効果があります。
これは、DOM Event の Event.preventDefault() メソッドに相当します。
テキストエリアへの入力をキャンセルする
// エレメントを作成する
var element = document.createElement("textarea");
// BODY のノードリストに登録する
document.body.appendChild(element);
// スタイルを設定
element.style.cssText = "width:400px; height:300px;";
// アタッチイベントに対応している
if(element.attachEvent){
// キーボードを押した時に実行されるイベント
element.attachEvent("onkeypress",function (e){
// デフォルトの動作をキャンセル
return false;
});
}
■イベント通知の伝達を終了する
イベントの伝達(バブリング)を終了するには、cancelBubble プロパティを使用します。
true 値をセットします。
同じイベントに他のリスナーが登録されている場合、それらの処理が終わるまでは中断しません。
これは、DOM Event の Event.stopPropagation() メソッドに相当します。
イベントの伝達を終了する
<html>
<body>
<div style="width:400px; height:300px; background:#fcc;">
<span style="font-size:32px;">あいうえお</span>
</div>
<script type="text/javascript">
<!--
// ------------------------------------------------------------
// DOM オブジェクトのすべての子孫を検索する関数
// ------------------------------------------------------------
function DomNodeFindAllDescendants(node,func){
function f(n){
var nodes = n.childNodes;
var i;
var num = nodes.length;
var a = new Array();
for(i=0;i < num;i++){ a[i] = nodes[i]; }
for(i=0;i < num;i++){
node = func(a[i]);
if(node){ return node; }
node = f(a[i]);
if(node){ return node; }
}
return null;
}
return f(node);
}
// アタッチイベントに対応している
if(window.attachEvent){
// ------------------------------------------------------------
// 要素にリスナーを登録する関数
// ------------------------------------------------------------
// リスナーA
function ElementAttachEventMouseClickA(current){
// アタッチイベントに対応しているか
if(!(current.attachEvent)) return;
// 要素にリスナーを登録
current.attachEvent("onclick" , function (e){
console.log("リスナーA");
console.log("カレント:" + current + "(" + current.nodeName + ")");
console.log("---");
// BODY 要素である場合、イベントの伝達を終了する
if (current.tagName == "BODY") {
// イベント通知の伝達を終了する
e.cancelBubble = true;
}
});
}
// リスナーB
function ElementAttachEventMouseClickB(current){
// アタッチイベントに対応しているか
if(!(current.attachEvent)) return;
// 要素にリスナーを登録
current.attachEvent("onclick" , function (e){
console.log("リスナーB");
console.log("カレント:" + current + "(" + current.nodeName + ")");
console.log("---");
// BODY 要素である場合、イベントの伝達を終了する
if (current.tagName == "BODY") {
// イベント通知の伝達を終了する
e.cancelBubble = true;
}
});
}
// ------------------------------------------------------------
// すべてのフェーズでリッスンを開始
// ------------------------------------------------------------
// ドキュメントにリスナーAを登録
ElementAttachEventMouseClickA(document);
// ドキュメントにリスナーBを登録
ElementAttachEventMouseClickB(document);
// コールバック関数を使って、ドキュメントのすべての子孫を検索
DomNodeFindAllDescendants(document,function (node){
// ドキュメントの子孫にリスナーAを登録
ElementAttachEventMouseClickA(node);
// ドキュメントの子孫にリスナーBを登録
ElementAttachEventMouseClickB(node);
// 検索を継続
return null;
});
}
//-->
</script>
</body>
</html>
■ EventObj オブジェクトを生成する
EventObj オブジェクトを作成するには、document.createEventObject() メソッドを使用します。
イベントを発行する方法については、こちらで解説しています。
document.createEventObject( EventObj ) :EventObj
第01引数(略可) | EventObj | 別の EventObj オブジェクトを複製したい場合に指定する |
戻り値 | EventObj | 新しい EventObj オブジェクト |
イベントオブジェクトを作成
// イベントオブジェクトを作成
var event_obj = document.createEventObject();
// 出力テスト
console.log(event_obj);
イベント関連のメソッドについて
■イベント関連のメソッドについて
メソッド名 | 説明 |
attachEvent() | リスナーを登録して、イベントの通知を受け取る。 |
detachEvent() | リスナーを除外して、イベントの通知を止める。 |
fireEvent() | イベントを発行する。 |
イベントの通知を受け取る
■コールバック関数を登録して、イベントの通知を受け取る
イベントの通知を受け取るには、 attachEvent メソッドを使用します。
Internet Explorer で使用すると、必ず専用の仕様で動作します。
Object.attachEvent ("イベント名" , コールバック関数 ) :Boolean
第01引数 | String | イベント名を指定。接頭の on は省略しない。 |
第02引数 | Function | コールバック関数を指定。 |
戻り値 | Boolean | アタッチに成功した場合 true、失敗した場合 false が得られる。 |
■第01引数 イベント名
監視したいイベントハンドラ名を指定します。
例えば、"onload" や、"onmousemove" などを指定します。
■第02引数 コールバック関数
システムがイベントを発行したときに、実行して欲しいコールバック関数を指定します。
マウスボタンをクリックしたときに実行されるイベント
// ------------------------------------------------------------
// マウスボタンをクリックしたときに実行される関数
// ------------------------------------------------------------
function MouseClickFunc(e){
// 出力テスト
console.log(e);
}
// ------------------------------------------------------------
// アタッチイベント
// ------------------------------------------------------------
// アタッチイベントに対応している
if(document.attachEvent){
// イベントのリッスンを開始する
document.attachEvent("onclick" , MouseClickFunc);
}
■リスナーの多重登録に注意
第01~02引数の指定がすべて同一である場合、リスナーの登録を試みても2重に登録されることはありません。
第01~02引数の指定に1つでも相違がある場合、リスナーの登録を試みるたびに多重に登録されていきます。
第02引数に、直接無名関数を渡している場合は、新規に関数を生成しているので注意します。
■イベントの通知の受け取りを止める
イベントの通知の受け取りを止めるには、detachEvent を使用します。
attachEvent メソッドで使用した、第01~02引数と同じパラメータを指定します。
Object.detachEvent ("イベント名" , コールバック関数 ) :void
第01引数 | String | 登録時に指定した、イベント名。 |
第02引数 | Function | 登録時に指定した、コールバック関数。 |
戻り値 | void | なし |
イベントの通知の受け取りを止める
// ------------------------------------------------------------
// マウスボタンをクリックしたときに実行される関数
// ------------------------------------------------------------
function MouseClickFunc(e){
console.log("マウスボタンをクリックした");
}
// ------------------------------------------------------------
// アタッチイベント
// ------------------------------------------------------------
// アタッチイベントに対応している
if(document.attachEvent){
// イベントのリッスンを開始する
document.attachEvent("onclick" , MouseClickFunc );
// イベントのリッスンを終了する
document.detachEvent("onclick" , MouseClickFunc );
}
■無名関数を使ったリスナーの登録を解除するには?
無名関数内でリムーブ処理を行う必要があります。
互換性を考慮する場合、そもそも匿名関数を直接渡さない方がいいでしょう。
■ arguments.callee プロパティを使用する
arguments.callee プロパティから、自身の関数を取得する事ができます。
ただし、strict モードでは、利用できません。
無名関数を使ったイベントのリッスンを終了する(strict モードでは不可能)
// アタッチイベントに対応している
if(document.attachEvent){
// ------------------------------------------------------------
// イベントのリッスンを開始する
// ------------------------------------------------------------
document.attachEvent("onclick" , function (e){
console.log("マウスボタンをクリックした");
// イベントのリッスンを終了する
document.detachEvent("onclick" , arguments.callee);
});
}
■ 関数リテラルに関数名を記述する
関数リテラルに関数名を記述すると、自身の関数を取得する事ができます。
この方法は、Internet Explorer 8 以前では機能しません。
無名関数を使ったイベントのリッスンを終了する(IE8 以前では不可能)
// アタッチイベントに対応している
if(document.attachEvent){
// ------------------------------------------------------------
// イベントのリッスンを開始する
// ------------------------------------------------------------
document.attachEvent("onclick" , function callee(e){
console.log("マウスボタンをクリックした");
// イベントのリッスンを終了する
document.detachEvent("onclick" , callee);
});
}
イベントを発行する
■イベントを発行する
イベントを発行するには、fireEvent() メソッドを使用します。
カスタムイベントを発行する事はできません。
発行可能なイベントは、既存のイベントのみです。
また、Window オブジェクトも対応していません。
Object.fireEvent ( "イベント名" , EventObj ) :Boolean
第01引数 | Event | イベント名を指定。未対応イベントを指定するとエラーが発生する。 |
第02引数(略可) | EventObj | リスナーに渡す EventObj を指定。省略した場合、空の EventObj が自動生成される。 |
戻り値 | Boolean | true の場合送出に成功。イベントの伝達を中止した場合も true。 false の場合送出に失敗。リスナーがキャンセルを要求した場合も false。 |
■既存イベントの発行について
既存イベントを発行して、ブラウザを制御する事はできません。
例えば、onmousemove イベントを発行して、OS のマウスカーソルを移動できるわけではありません。
イベントを発行すると、任意のエレメントに登録したコールバック関数が実行されるだけです。
■使用例
onclick イベントを手動的に発行する
// アタッチイベントに対応している
if(document.attachEvent){
// ------------------------------------------------------------
// マウスボタンをクリックしたときに実行されるイベント
// ------------------------------------------------------------
document.attachEvent("onclick" , function (e) {
console.log("イベントの通知を受け取った");
});
// ------------------------------------------------------------
// イベントオブジェクト
// ------------------------------------------------------------
// イベントオブジェクトを作成
var event_obj = document.createEventObject();
// マウス用のプロパティを変更
event_obj.clientX = 111;
event_obj.clientY = 222;
event_obj.screenX = 333;
event_obj.screenY = 444;
// ------------------------------------------------------------
// Document からイベントを送出
// ------------------------------------------------------------
document.fireEvent("onclick" , event_obj);
}