jQuery でアニメーションの前後に .css() とか .addClass() とかしたい時に .queue() を使う
やりたいこと
jQuery の animate
メソッドを使って見た目を作っている時、アニメーションの完了後にクラスを付与したいとか、 CSS を変更したいというようなことはよくある。これをエレガントな感じに書きたい。
何も考えずに jQuery っぽく書いてみる
$('.target') .animate({ left: '100px', top: '100px' }, 500, 'swing') .css('background-color', 'red');
これだとうまくいかない。アニメーションが終了した時に背景色が赤になってほしいが、アニメーションが始まったと同時に赤くなってしまう。
animate
のコールバック関数を指定する
解決策のひとつとして、 animate
メソッドの最後の引数にコールバック関数を指定する方法がある。指定したコールバック関数は、アニメーションが完了した直後に実行されることになっている。
$('.target') .animate({ left: '100px', top: '100px' }, 500, 'swing', function () { // アニメーションが完了した後に実行される $(this).css('background-color', 'red'); });
正常に赤くなってくれた。これの問題点は、連なる動作が増えるとどんどん入れ子が深くなってしまうことだ。
$('.target').animate({ left: '100px', top: '100px' }, 500, 'swing', function() { $(this).css('background-color', 'red').animate({ top: '0' }, 500, 'swing', function() { $(this).css('background-color', 'green').animate({ 'left': '0' }, 500, 'swing', function() { $(this).css('background-color', 'blue'); }); }); });
$.Deferred
で連結する
かと言って、この程度の処理で Deferred の仕組みを使うのは少し冗長な感じがある……。
var tgt = $('.target'); $.when(tgt.animate({ left: '100px', top: '100px' }, 500, 'swing')) .then(function () { tgt.css('background-color', 'red'); }) .then(function () { return tgt.animate({ top: '0' }, 500, 'swing'); }) .then(function () { tgt.css('background-color', 'green'); }) .then(function () { return tgt.animate({ left: '0' }, 500, 'swing'); }) .then(function () { tgt.css('background-color', 'blue'); });
.queue()
メソッドを使う
そもそも、 jQuery の animate
メソッドなどは、 jQuery 内部のキューという順番待ちの仕組みで制御されている。この仕組みを使い、アニメーションが終わったら次のを実行して……。という順次処理を実現している。
したがって、このキューに任意の処理を追加出来ればいい。 jQuery にはそのためのメソッド queue
が用意されている。
queue
を使った書き方をすると以下の様なコードになる。
$('.target') .animate({ left:'100px', top:'100px' }, 500, 'swing') .queue(function () { $(this).css('background-color', 'red').dequeue(); }) .animate({ top:'0' }, 500, 'swing') .queue(function () { $(this).css('background-color', 'red').dequeue(); }) .animate({ left:'0' }, 500, 'swing') .queue(function () { $(this).css('background-color', 'red').dequeue(); });
注意点として、 queue
メソッドの引数に指定する関数内で、 $(this).dequeue()
をする必要がある。 dequeue
は処理が終了したという合図になるため、記述しないとキューの処理がそこで止まったままになってしまう。