jQuery の hover() について調べたことのまとめ
hover() は mouseenter と mouseleave を同時にセットする
http://docs.jquery.com/Events/hover の引数の名前付けを見て、hover は mouseover と mouseout を同時に指定するものだと思っていたが違うらしい。
jquery-1.2.6.js の 2278 行付近
hover: function(fnOver, fnOut) { return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut); },
とあるように mouseenter と mouseleave に対して指定するものである。
over/outと enter/leave の違いは、http://docs.jquery.com/Events/mouseover の Demo みるとよくわかる。
ある領域 A にカーソルが載ったときに、領域 A 内に動的にブロック B を表示するという処理を次のようなに作っていた。
http://tilfin.googlepages.com/overout.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="content-script-type" content="text/javascript"> <script src="jquery-1.2.6.js"></script> <title>jquery mouseover / mouseout</title> <style type="text/css"><!-- #A { color:#fff; background-color:blue; border:1px solid #000; width:300px; height:200px; position:relative; } #B { color:#fff; background-color:red; border:1px solid #000; display:none; width:200px; height:100px; position:absolute; bottom:0; right:0; } #debug p { margin:0; line-height:110%; font-size:9pt; } //--></style> <script><!-- $(document).ready(function(){ $("#A") .mouseover(function(){ $("#debug").append("<p>A: mouseover</p>"); $("#B").appendTo(this).show(); }) .mouseout(function(){ $("#debug").append("<p>A: mouseout</p>"); $("#B").hide().appendTo(document.body); }); }); //--></script> </head> <body> <div id="A">A</div> <div id="B">B</div> <div id="debug"></div> </body> </html>
しかし、これだと表示されたブロック B にカーソルが載ったとき、A の mouseout が発生するためちらつきが起こってしまう(これは Firefox のときで IE ではちらつきではなく消えたままになった)。
http://tilfin.googlepages.com/enterleave.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="content-script-type" content="text/javascript"> <script src="jquery-1.2.6.js"></script> <title>jquery mouseenter / mouseleave</title> <style type="text/css"><!-- #A { color:#fff; background-color:blue; border:1px solid #000; width:300px; height:200px; position:relative; } #B { color:#fff; background-color:red; border:1px solid #000; display:none; width:200px; height:100px; position:absolute; bottom:0; right:0; } #debug p { margin:0; line-height:110%; font-size:9pt; } //--></style> <script><!-- $(document).ready(function(){ $("#A").hover(function(){ $("#debug").append("<p>A: mouseenter</p>"); $("#B").appendTo(this).show(); }, function(){ $("#debug").append("<p>A: mouseleave</p>"); $("#B").hide().appendTo(document.body); }); /* $("#A") .bind("mouseenter", function(){ $("#debug").append("<p>A: mouseenter</p>"); $("#B").appendTo(this).show(); }) .bind("mouseleave", function(){ $("#debug").append("<p>A: mouseleave</p>"); $("#B").hide().appendTo(document.body); }); */ }); //--></script> </head> <body> <div id="A">A</div> <div id="B">B</div> <div id="debug"></div> </body> </html>
として hover (mouseenter/mouseleave) を使うとうまくいった。
これは jquery のソースをみると下記のようにサブ要素上にまだあるかイベント内でフックして判定しているからである。
jQuery.event.special.mouseleave.handler
handler: function(event) { // If we actually just moused on to a sub-element, ignore it if ( withinElement(event, this) ) return true; // Execute the right handlers by setting the event type to mouseenter event.type = "mouseenter"; return jQuery.event.handle.apply(this, arguments); }
ちなみにこのような動的な方法ではなく、元々
hover を unbind する方法
hover はイベントタイプとして存在するわけではないので、$("#A").unbind("hover") とは書けない。
$("#A").unbind("mouseover").unbind("mouseout");
とするのも駄目である。これだと前述のように、mouseenter と mouseleave からイベントバインドされているため上記の jQuery.event.special.mouseleave.handler がフックされたまま残ってしまうからだ。
$("#A").unbind("mouseenter").unbind("mouseleave");
とするのが正しい。