三章第六回 mouseoverとmouseout
このページの最終更新日:
今回は、mouseoverとmouseoutという2つのイベントについて詳しく解説します。
<!doctype html>
<html>
<head>
<title>test</title>
<style type="text/css">
p{
background-color:yellow;
width:300px;
height:300px;
}
</style>
</head>
<body>
<p onmouseover="console.log('mouseover');" onmouseout="console.log('mouseout');">test</p>
</body>
</html>
このサンプルでは黄色い部分がp要素で、これにはmouseoverとmouseoutのイベントが設定されています。マウスがp要素の外からp要素の上にはいるとmouseover、p要素の上からp要素の外にでるとmouseoutが発生しているのがわかります。つまり、mouseoverとmouseoutというイベントは、ある要素の上にマウスが入ったときと出たときにそれぞれ発生するのです。ある部分にマウスが移動するとなにかが動くというような動作は、今でこそCSSを用いて作られることが多いですが、一昔前はJavaScriptのこれらのイベントを使って実装されていました。現在でも複雑なことをしたければこれらのイベントにお世話になる機会があるでしょう。
さて、ここで、body要素に注目してください。ページ上の黄色い部分はp要素ですが、それ以外の部分はbody要素です。p要素はbody要素の子ではあるものの、マウスイベントを扱う場合はbody要素の領域はその直下の部分のみとなり、黄色い部分(p要素の部分)はbody要素の領域と見なされません。
body要素の上からp要素の上にマウスが移動する場合を考えてみましょう。マウスは依然としてbody要素の中にある(p要素はbody要素の中にあるので)と考えられますが、上述の領域の観点ではp要素の中(p要素の領域)はbody要素の領域ではないため、body要素から見ると、p要素という別の領域にマウスがいってしまったことになります。よって、この場合body要素ではmouseoutイベントが発生するということになります。
このとき当然p要素ではmouseoverイベントが発生しています。つまり、2つの異なる要素でmouseoverイベントとmouseoutイベントが同時に発生することになります。
同様に、p要素の上からbody要素にマウスが移動するときはp要素ではmouseoutが発生する一方、body要素ではmouseoverが同時に発生します。
このように、mouseoverとmouseoutは対になって発生します。さらに、三章第三回で解説したイベントバブリングの概念を加えると、p要素で発生したmouseoverやmouseoutは親へと伝わっていき、最終的にどちらもdocumentに到達します。
つまり、どこからどこへマウスが移動しようと、mouseoverとmouseoutがdocumentに伝わることになり、この2つは本質的に同じイベントであるということができます。
そこで、DOMでは、この2つを統一的に、まとめて扱う方法が用意されています。mouseover/mouseoutイベントのイベントオブジェクトには、relatedTargetというプロパティが用意されています。
このrelatedTargetは、今のイベントと対になるイベントが起こった要素を表しています。例えば、body要素からp要素にマウスを動かしたとき、p要素でmouseoverが発生したから、targetは当然p要素です。このとき、マウスがbody要素の上から離れたことで、対になるmouseoutがbody要素で発生するはずです。このbody要素がrelatedTargetになります。
より分かりやすく言えば、mouseoverイベントでは、マウスの移動先がtargetプロパティに入り、移動元がrelatedTargetプロパティに入ります。mouseoutイベントの場合は逆になります。次のサンプルで確かめてみてください。
<!doctype html>
<html>
<head>
<title>test</title>
<style type="text/css">
p{
background-color:yellow;
width:300px;
height:300px;
}
</style>
</head>
<body>
<p>test</p>
<script type="text/javascript">
var listener = function(ev){
console.log("target:", ev.target, "relatedTarget:", ev.relatedTarget);
};
document.addEventListener('mouseover' , listener,false);
</script>
</body>
</html>
余談ですが、このサンプルで試しているとp要素やbody要素だけでなくhtml要素が出現することがあるのに気づくと思います。実は、ページ上表示されている領域全てがbody要素ではありません。たまに罠になりますから気をつけましょう。