Javascript:イベントバブル、onClick, onMouseOver(Out), onMouseEnter(Leave)についてのメモ
こちらで教えてもらったことを元に、「下位要素ノードで発生したイベントは、上位要素方向へ伝播する」というイベントバブルを軽く理解した上で、
======= onClick =======
「event.bubbles」を参考に、下(Sample1)の色のついた領域のどこがクリックされたかを表示させるスクリプトを書いてみました。
Sample1
p span
どこがクリックされたかをここに表示します。
ソース(CSSは大きさ、色など、文字の太さを指定しているだけなので省略)
JavaScript↓
function clickTest(evt){
t=evt.target || evt.srcElement;
document.getElementById("clickedAera").innerHTML=t.tagName+" がクリックされました。"
}
html↓
<div id="clickTest" onClick="clickTest(event);">div <p>p <span>span</span> <input type="button" value="input"> </p> </div> <p id="clickedAera">どこがクリックされたかをここに表示します。</p>
【メモΦ(。。)】
- イベント発生源:event.target
(IE は event.srcElement) - 現在 onclick 属性が実行されているノード:event.currentTarget
(IE にはこれに該当するプロパティがないので this で代用)
======= onMouseOver / onMouseOut =======
次に、少しやっかいな(と思った)mouseOverとmouseOut。何がやっかいかというと、境界線をまたげば、同じイベントでもそれは立場(要素)によってmouseOutでもありmouseOverでもあるんですが、これにイベントバブルが絡むと、同じ要素で同時にmouseOverとmouseOutが起きるということです。
「イベントバブル、マウスオーバーなどに関して – JavaScript – 教えて!goo」にも書いたとおり、div内で、divの中のpに入るとき、一旦divはmouseOutしてからmouseOverになるんですが、その根拠とおぼしき事が「掲示板/JavaScript質問板/過去ログ/一覧/ 右クリで呼び出しができるならば、ボタン3では? – TAG index Webサイト」の後半で書かれてあります。
詳しくはそちらを参照してもらうとして、結論として「event.target」と「event.relatedTarget」(IEでは「event.toElement」と「event.fromElement」)の関係で納得できました。
Sample2
ソース(CSSは大きさ、色など、文字の太さを指定しているだけなので省略)
JavaScript↓
function mouseOverOutOver(evt){
var t = evt.target || evt.toElement; // mouseOver した要素
var f = evt.relatedTarget || evt.fromElement; // mouseOut した要素
document.getElementById("whereMouseIs").innerHTML=
"マウスは "+f.id+" から "+t.id+" に移動しました。"
}
function mouseOverOutOut(evt){
var t = evt.relatedTarget || evt.toElement; // mouseOver した要素
var f = evt.target || evt.fromElement; // mouseOut した要素
document.getElementById("whereMouseIs").innerHTML=
"マウスは "+f.id+" から "+t.id+" に移動しました。"
}
html↓
<div id="outside">outside <div onMouseOver="mouseOverOutOver(event);" onMouseOut="mouseOverOutOut(event);" id="div">div <p id="p">p</p> (白いところ)ul↓ <ul id="ul"> <li id="li1"><a id="a1">a1</a> li1</li> <li id="li2"><a id="a2">a2</a> li2</li> <li id="li3"><a id="a3">a3</a> li3</li> <li id="li4"><a id="a4">a4</a> li4</li> </ul> </div> </div> <p id="whereMouseIs">マウスの状態をここに表示します。</p>
【メモΦ(。。)】
マウスが境界線をまたぐとき、
- mouseOver(Out)の対象となる要素 = event.Target
(IEでは常にmouseOverした要素がevent.toElement) - event.TargetがmouseOver(Out)したときにmouseOut(Over)した要素 = event.relatedTarget
(IEでは常にmouseOutした要素がevent.fromElement)
┌───────────── mouseOver─────────────┐
│ │ │
│(マウスの動き)⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒ │
│ │ │
│(IE以外)event.relatedTarget │ event.Target │
│(IE )event.fromElement │ event.toElement │
└───────────────┴───────────────┘
┌───────────── mouseOut ─────────────┐
│ │ │
│(マウスの動き)⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒⇒ │
│ │ │
│(IE以外)event.Target │event.relatedTarget │
│(IE )event.fromElement │event.toElement │
└───────────────┴───────────────┘
Sample2のプログラムでは、例えばマウスがulにいるのかdivにいるのかは分かりますが、「divの中のul」であってもulにいる限りはdivの外側とみなされてしまいます。
では、ある領域の「内側」にいるのか「外側」にいるのかを判別するにはどうすれば良いか。Sample3のような図で「area2」の中か外かを判別する例を考えてみます。
area2にonMouseOver(Out)イベントが起きるのは、area2内側で境界線をマウスがまたぐときです。その時のマウスの行き先は、IE以外ではonMouseOverの場合はevent.Target、onMouseOutの場合はevent.relatedTarget、IEの場合はいつでもevent.toElementであることはSample2で確認したとおりです。
こうして、マウスの行き先のエレメントを取得した上で、行き先のエレメント、その親、さらにその親、さらにその親、、、のいずれもarea2に該当するものがない場合、「area2の外側に出た」(逆に、どれか一つでもarea2であれば、マウスは内側にいる)ということができます。
(area1~4の位置関係から判定しても良いですが、ロジックを一般化するために)
下のSample3では、for(……){……}の内部で行き先の要素、その親、さらにその親、さらにその親……が「area2」であるかどうか、順次調べようとして「if(tmp.id=”area2″){……}」と記述したのですが、そうするとなぜか表示が崩れる(理由は現在追求中)ので、「要素のid名+親要素のid名+その親要素のid名+……」という文字列を作って、その中に「area2」という文字が含まれるかどうかで判別する(文字列.indexOf(検索文字列、検索位置)で検索文字位置(存在しない場合は「-1」)を返す)プログラムにしてみました。
Sample3
ここに、マウスがarea2の外側か内側かを表示します。
ソース(CSSは大きさ、色など、文字の太さを指定しているだけなので省略)
JavaScript↓
function mouseInsideOutsideOver(evt){
var t = evt.target || evt.toElement; // mouseoOver した要素
var elmnts=""; // 「その要素から親方向へエレメントのid名を連ねた文字列」の初期化
for (tmp=t;tmp;tmp=tmp.parentNode){
elmnts=elmnts+tmp.id
}
if(elmnts.indexOf("area2")==-1){ // 「area2」という文字列が含まれなければ
msg="外側";
}
else msg="内側";
document.getElementById("whereMouseInsideOutside").innerHTML="マウスは、area2 の"+msg+"の "+t.id+" にいます。";
}
function mouseInsideOutsideOut(evt){
var t = evt.relatedTarget || evt.toElement; // mouseoOver した要素
var elmnts=""; // 「その要素から親方向へエレメントのid名を連ねた文字列」の初期化
for (tmp=t;tmp;tmp=tmp.parentNode){
elmnts=elmnts+tmp.id
}
if(elmnts.indexOf("area2")==-1){ // 「area2」という文字列が含まれなければ
msg="外側";
}
else msg="内側";
document.getElementById("whereMouseInsideOutside").innerHTML="マウスは、area2 の"+msg+"の "+t.id+" にいます。";
}
html↓
<div id="area1">area1 <div onMouseOver="mouseInsideOutsideOver(event)" onMouseOut="mouseInsideOutsideOut(event)" id="area2">area2 <div id="area3">area3 <div id="area4">aera4 </div> </div> </div> </div> <p id="whereMouseInsideOutside">ここに、マウスがarea2の外側か内側かを表示します。</p>
======= onMouseEnter / onMouseLeave =======
ちなみに「onMouseEnter」「onMouseLeave」というハンドラはその中に入ったか出たときにイベントが発生するので便利ですが、これが有効なのはIEとOperaだけのようなので、残念です。
Sample4では、Area1(2,3,4)の中にマウスがいる(in)かいない(out)かの状態を下の表に表示します(ただし、IE、Operaのみ)。
Sample4
| Area1 | Area2 | Area3 | Area4 | IE Operaのみ状態を表示 | IE Operaのみ状態を表示 | IE Operaのみ状態を表示 | IE Operaのみ状態を表示 |
|---|
ソース(CSSは大きさ、色など、文字の太さを指定しているだけなので省略)
JavaScript↓
function area1in() {
document.getElementById("area1InOut").innerHTML="in"
}
function area1out() {
document.getElementById("area1InOut").innerHTML="out"
}
function area2in() {
document.getElementById("area2InOut").innerHTML="in"
}
function area2out() {
document.getElementById("area2InOut").innerHTML="out"
}
function area3in() {
document.getElementById("area3InOut").innerHTML="in"
}
function area3out() {
document.getElementById("area3InOut").innerHTML="out"
}
function area4in() {
document.getElementById("area4InOut").innerHTML="in"
}
function area4out() {
document.getElementById("area4InOut").innerHTML="out"
}
html↓
<div id="mouseEnterLeaveArea1" onMouseEnter="area1in();" onMouseLeave="area1out();">area1 <div id="mouseEnterLeaveArea2" onMouseEnter="area2in();" onMouseLeave="area2out();">area2 <div id="mouseEnterLeaveArea3" onMouseEnter="area3in();" onMouseLeave="area3out();">area3 <div id="mouseEnterLeaveArea4" onMouseEnter="area4in();" onMouseLeave="area4out();">area4 </div> </div> </div> </div> <table> <thead> <th>Area1</th> <th>Area2</th> <th>Area3</th> <th>Area4</th> </thead> <tbody> <td id="area1InOut">IE Operaのみ状態を表示</td> <td id="area2InOut">IE Operaのみ状態を表示</td> <td id="area3InOut">IE Operaのみ状態を表示</td> <td id="area4InOut">IE Operaのみ状態を表示</td> </tbody> </table>
FC2ノウハウ


