【JavaScript】onmouseover/onmouseoutの振る舞い
どういうことかというと、例えば、
のように、親オブジェクトAの中に子オブジェクトB、孫オブジェクトCがいるような場合。
Aに対してonmouseover/onmouseoutを設定したとすると、直感的には、
- Aの外から内側に入った場合にのみ、overイベントが発生。
- Aから外に出た場合にのみ、outイベントが発生。
というのは、A~B間、B~C間の境界を移動した場合にも、当該イベントが発生してしまうからです。
たとえば、A→Bに動くと、一旦 out が発生してから改めて over が発生します。
つまり、一旦領域外に出てから、改めて入ったかのように振る舞ってしまうわけです。
さらに、A・B・C全てに対してonmouseover/onmouseoutを設定した日には、かなりいやらしい動作となってしまいます。
■動作サンプル
■サンプルソース
var w=window,d=w.document;
w.setEventHandler=(function(){
if (w.addEventListener) {
return function(obj,evt,handler){obj.addEventListener(evt,handler,false)};
}
else if (w.attachEvent) {
return function(obj,evt,handler){obj.attachEvent('on'+evt,handler)};
}
else {
return function(obj,evt,handler){var org=obj['on'+evt];obj['on'+evt]=function(){if(typeof org=='function')org();handler()}};
}
})(); // end of setEventHandler()
w.setMouseHandler=function(obj,evt,handler) {
var mouseHandler=function(curEvent,e) {
if (!e) e=w.event;
if (!e) return;
var prop=obj._MouseProp_;
var curStatus=prop.status;
if (curStatus==curEvent) return;
if (curStatus=='out') { // outer to inner
var fncArrayOver=prop.fncArrayOver;
for (var ci=0,len=fncArrayOver.length; ci<len; ci++) {
fncArrayOver[ci].apply(obj,[e]);
}
}
else { // inner to outer
var chkNode=e.toElement||e.relatedTarget;
while (chkNode) {
if (chkNode==obj) return;
chkNode=chkNode.parentNode;
}
var fncArrayOut=prop.fncArrayOut;
for (var ci=0,len=fncArrayOut.length; ci<len; ci++) {
fncArrayOut[ci].apply(obj,[e]);
}
}
prop.status=curEvent;
};
var prop=obj._MouseProp_;
if (!prop) {
prop=obj._MouseProp_={status:'out',fncArrayOver:[],fncArrayOut:[]};
w.setEventHandler(obj,'mouseover',function(e){mouseHandler('over',e)});
w.setEventHandler(obj,'mouseout',function(e){mouseHandler('out',e)});
}
if (evt=='mouseover') {
prop.fncArrayOver[prop.fncArrayOver.length]=handler;
}
else if (evt=='mouseout') {
prop.fncArrayOut[prop.fncArrayOut.length]=handler;
}
else {
w.setEventHandler(obj,evt,handler);
}
};
})();
setMouseHandler(object,event,handler)の方が、mouseover/mouseout専用のイベントハンドラ登録用関数になります。
- デフォルト(ハンドラ登録時)は"外"にいるものとして初期化。
- "外"において発生した'mouseover'により、"外"→"内"に移動したものとみなす。
- "内"にいるときに発生する'mouseover'は無視。
- "内"にいるときに'mouseout'が発生した場合、移動先のオブジェクトをevent.toElement(IE)もしくはevent.relatedTarget(Firefox他)で取得し、そこから親を辿っていって、イベントを設定したオブジェクトが見つからない場合にのみ、"外"へと移動したものとみなす。
2008/03/11(火) 01:57 | 固定リンク
| 記事の編集(管理者用)
「パソコン・インターネット」カテゴリの記事
- 動けるものも久しからず(2012.02.15)
- 5年以上も気付かない振り(2012.02.14)
- 探しものって、みつけにくいものですね…(2012.02.13)
- Norton Internet Securityでエラー: 「3043,1」(2011.07.13)
- アンケート:ブログ等で「続きを読む」リンクを見たら…(2010.11.05)
「覚書」カテゴリの記事
- 動けるものも久しからず(2012.02.15)
- Norton Internet Securityでエラー: 「3043,1」(2011.07.13)
- 終わりを惜しむ6タイトル(2010.12.19)
- ココでも:ココログ広場ユーザーのブログをキーワードで検索するサービスを試作(2010.10.29)
- ココログ用ReadMore:トップページの『》 続きを読む』をその場で展開するスクリプト(2010.11.06)


