[jQuery] mouseenter/mouseleaveとmouseover/mouseoutの違いとhover()

2013 年 3 月 30 日 Categories: jQuery | Tags:

基本

  • 通常、「mouseenter()/mouseleave()」、「mouseover()/mouseout()」のセットで使う。
  • 本来、mouseenterとmouseleaveイベントはInternet Explorer(IE)独自のもの。jQueryが内部でシミュレートし、クロスブラウザの機能にしている。
  • 大半の場合、「mouseenter()/mouseleave()」を使う(hover()と同じ)。

入れ子の状態について

あくまでHTMLの構造上(DOMツリーで)親と子の関係(入れ子の関係)にあるか否かが問題になる。CSSなどで見た目上、重なっているかどうかは関係ない。

下記のデモのように、重なっていない部分でも親要素からみれば、子要素のすべての領域が同一の領域ということになる。

よって、仮に見た目上、完全に両方の要素が離れていたとしても、子要素上でマウスカーソルが動けば、親要素でも各イベントが発生する。

入れ子状態にない場合

CSSで見た目上、上にある(z-indexが大きい)要素にのみ反応する。つまり、それぞれまったく別の領域として扱われる。

* おそらく、こちらのほうがわかりやすい。

違い

違いが出るのは、親要素と子要素が(部分的にでも)重なっていて、その重なりの部分でマウスカーソルが移動した場合。

mouseenter()/mouseleave()

子要素を親要素の一部として扱う

マウスカーソルが親要素から子要素に入ったり出たりしても、親要素にイベントは発生しない。

つまり、親要素ではそれぞれをまったく同一の領域として扱う。

mouseover()/mouseout()

基本、上記と同じだが、マウスカーソルがすでに親要素にあり、そこから重なっている子要素に移った場合、子要素はもちろん、親要素にも再びmouseoverイベントが発生する。

子要素から重なっている部分の親要素に移った場合、親要素にmouseoverイベントが発生し、その際、子要素だけでなく親要素にもmouseoutイベントが発生する。。

ポイント1:親要素と子要素をそれぞれ別の領域として扱う

子要素が親要素の領域を切り取ると考えるとわかりやすい。

親要素から見た場合、マウスカーソルが親要素から子要素に移ると、親要素から離れたとみなしてそこではmouseoutイベントが発生する。

逆にマウスカーソルが子要素から親要素へ移ると、親要素に入ってきたとみなしてそこではmouseoverイベントが発生する。

ポイント2:mouseoutイベントはいつでも発生する

子要素から親要素の重なった部分へ移動した場合のことを考えよう。

このとき、子要素でmouseleaveとmouseoutが起こるのは当然だが、親要素でもmouseoutが発生する。

要するにこの場合、親要素ではmouseoverとmouseoutが同時に発生する

ここがわかりづらいのだが、端的にいえば「重なった子要素と親要素間の移動では、子要素のイベントがすべて親要素でも発生する」ということになる。

  • 子でmouseover => 親でもmouseover
  • 子でmouseout => 親でもmouseout

これに、親要素自体のmouseover/ mouseoutイベントが発生するので、領域が重なっている場合がややこしい。

デモ

親要素
mouseenter 0
mouseleave 0
mouseover 0
mouseout 0
子要素
mouseenter 0
mouseleave 0
mouseover 0
mouseout 0

要素が隠れている場合

CSSの「display: none;」や「visibility: hidden;」で要素が表示されていない場合、マウスイベントは発生しない。

hover()

hover()は、内部でmouseenter()/mouseleave()にイベントハンドラを登録している(バインドしている)。

// jQuery 1.9.1
jQuery.fn.hover = function( fnOver, fnOut ) {
	return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
};

よって、イベントハンドラを外したい(unbindしたい)場合は以下のようにする。

jQuery(target).unbind('mouseenter mouseleave')

なお、CSSの擬似セレクタである「:hover」とは異なり、マウスカーソルが対象から外れた場合に自動で元の状態に戻してくれるわけではない。

たとえば、マウスオーバーしたときだけ要素の色を変えた場合、第2引数のfnOutで自前で元の状態に戻さなければならない。

jQuery("#sample").hover(
	// fnOver
	function () {
		jQuery(this).css("background-color", "red");
	},
	// fnOut
	function () {
		jQuery(this).css("background-color", "transparent");
	}
);