JavaScript Advent Calendar 20105日目のago(@kyo_ago)です。
jQueryのソースを眺めててjQuery.stopに引数があることに気づいたので調べてみました。
まず、簡単なスライドダウンメニューを作ってみたいと思います。
jQuery.stop 1 - jsdo.it - share JavaScript, HTML5 and CSS
JS部分は以下の通りです。
$(function () {
$('div').hover(function () {
$(this).find('ul').slideDown();
}, function () {
$(this).find('ul').slideUp();
});
});
少し触ると分かると思いますが、マウスがmenuから外れた後も何度も.slideDown、.slideUpが実行されるため非常に操作性が悪いです。
jQueryはアニメーションが複数同時に呼ばれた場合、先に呼ばれたアニメーションが終了するまで次のアニメーションが呼び出されないように実装されており、このためユーザの操作で呼び出されるアニメーションをそのまま実装するとこういった動作になってしまいます。
こういった問題を解決するためにjQueryには.stopというメソッドが用意されており、このメソッドを呼び出すとその時点で実行されているアニメーションを停止させることが出来ます。
jQuery.stop 2 - jsdo.it - share JavaScript, HTML5 and CSS
JS部分は以下の通りです。
$(function () {
$('div').hover(function () {
$(this).find('ul').stop().slideDown();
}, function () {
$(this).find('ul').stop().slideUp();
});
});
.stop無しのものにあった「マウスがmenuから外れた後も何度も.slideDown、.slideUpが実行される」問題は解決しています。
ただこのコードでも速い速度でmenu1?menu3のあいだを何度もマウスが往復しているとだんだんsub1?sub3の高さが減っていくと思います。
これは.stopが単純にアニメーションを停止させるだけなので、.slideDownの途中で呼び出された場合、その時点のheightが次回以降のheightとして認識されることが原因です。
(「.slideDownの途中で.stop」->「.stopが呼び出された時点のheightがその要素のheightとして設定されたままになる」->「次の.slideDownも前回のheightまでしか高さが変化しない」)
jQueryはこれに関しても対応が用意されており、.stopの第2引数(jumpToEnd)にtrueを渡してやると、アニメーションを停止した上で停止されたアニメーションの終了時点の表示まで処理を飛ばしてくれます。
jQuery.stop 3 - jsdo.it - share JavaScript, HTML5 and CSS
JS部分は以下の通りです。
$(function () {
$('div').hover(function () {
$(this).find('ul').stop(true, true).slideDown();
}, function () {
$(this).find('ul').stop(true, true).slideUp();
});
});
どうでしょうか?最初のコードに対して.stop(true, true)を追加しただけですが、これだけで普通に使えるスライドダウンメニューになったのではないかと思います。
ちなみに第1引数(clearQueue)はその時点で実行待ちになっているアニメーションを全て停止させる指定ですが念のためtrueを指定しています。
(こういったユーザ動作で発生するアニメーションの場合、同時に実行されることは無いと思います)
個人的には非常に便利だと思うんですが、現状日本語のリファレンスサイトには解説されていないため、ドキュメントを確認したい場合本家APIの.stopを確認してください。