読んで覚える、触って体験!JavaScript&CSS3~gihyo.jp×jsdo.it presents

第5回jQueryでアニメーション(解答編)

はじめに

前回はjQueryのアニメーション機能について解説し、以下のようなタブのUIをjQueryのアニメーションで切り替えるというお題を出しました。

jQueryアニメーションのお題 - jsdo.it - share JavaScript, HTML5 and CSS

今回このお題をforkしてもらったコードを紹介しながら解説していきます。

模範解答

まずは模範解答として、以下の作品を紹介します。

forked from: jQueryアニメーションのお題 | 第4回 jQueryでアニメーション - jsdo.it - share JavaScript, HTML5 and CSS

この作品はページ切り替えの部分を以下のように変更しているだけです。

$currentPage.fadeOut("fast");
$targetPage.slideDown();

1行目の部分で現在のページがフェードアウトして2行目で表示させるページがスライドダウンで表示されます。jQueryを使うととても簡単にアニメーションすることができるということがわかる作品です。

前回解説したように、jQueryにはあらかじめ用意されているアニメーションのショートカットがあり、fadeIn、fadeOut、slideUp、slideDownなどがそれにあたります。この作品を見てもわかるように、これらの組み合わせだけでも実用的なアニメーションを簡単に作ることできます。

今回のお題のポイント

コールバックを使う

今回のお題のポイントをいくつか解説したいと思います。まず1つ目は、二つのアニメーションを同時に行う場合にコールバックを用いることを検討するという点です。例えばスライドアップの後スライドダウンで表示するようなアニメーションにしたい場合以下のように書いたとします。

$currentPage.slideUp();
$targetPage.slideDown();

これでうまくいくように思いますが、実際はこのようになります。

forked from: jQueryアニメーションのお題 - jsdo.it - share JavaScript, HTML5 and CSS

これだとスライドアップとスライドダウンが同時に実行されるため意図した動作になりません。そこでスライドアップが終わった後にスライドダウンを行うという動作にするため、以下のように変更します。

$currentPage.slideUp(function() {
  $targetPage.slideDown();
});

slideUpの第一引数に関数を指定すると、スライドアップが終わったあとに設定した関数を実行するということになります。これは以下のように動きます。

forked from: jQueryアニメーションのお題 - jsdo.it - share JavaScript, HTML5 and CSS

これで意図した動作になりました。ただしアニメーションによっては同時に行うことを意図していることもあると思うので必ずしもコールバックを使えばいいというわけではありません。

タブを切り替える条件を設定する

forked from: jQueryアニメーションのお題 - jsdo.it - share JavaScript, HTML5 and CSS

この作品はアニメーション自体もイージングを使って透明度なども同時に切り替えていて工夫されているのですが、コメントにある「カレントのタブ以外を選択、かつコールバック処理中でない場合に切り替え実行」というところが工夫されていました。具体的には以下の部分です。

if(($tabs.data('currentTabId') !== tabId) && ($targetPage.is(':not(:animated)'))) {
  // アニメーションの処理
}

このような処理を行っていない場合、現在のタブを押してしまったときや、アニメーションの途中に他のタブを押したときに意図しない動作になる可能性があります。今回のお題ではアニメーションをすることが目的だったのでそこまでの処理は実装しなくてもいいのですが、実際のサイトやアプリケーションで実装する場合にはこのような場合の挙動も考えて実装することはとても重要です。

工夫されていた作品

jQuery組み込みのアニメーション関数だけでなく、ちょっとした一手間で変わったアニメーションをする作品や、コードをかなり変更して独自のアニメーションを実装した作品などたくさんありましたので紹介したいと思います。

leftの値を変えてスライドさせる

forked from: jQueryアニメーションのお題 - jsdo.it - share JavaScript, HTML5 and CSS

この作品はfadeInやfadeOutに一手間加えることで面白い動きになっています。実際にアニメーションを行っているコードは以下のようになっています。

$currentPage.animate({left:-420}).fadeOut();
$targetPage.animate({left:20}).fadeIn();

フェードイン、フェードアウトの前にleftの値をアニメーションさせているだけです。これだけで、元々表示されているコンテンツはフェードアウトする前に左にスライドするように消え、その後次のページがフェードインで表示されます。普通にフェードイン、フェードアウトするのにたったこれだけ足すだけでまったく変わったアニメーションになるという好例です。

specialEasingやdelayを使った作品

forked from: jQueryアニメーションのお題 - jsdo.it - share JavaScript, HTML5 and CSS

上記作品は、specialEasingでwidthとheightそれぞれでイージング関数を別のものにしたり、delayで次のアニメーションを遅らせたりと、工夫されたアニメーションで実装されています。

$currentPage.hide();
$targetPage
  .css({display:'block',width:0,height:0})
  .animate({
    width:200,
    height:300
  }, {
    duration: 500,
    specialEasing: {
      width: 'linear',
      height: 'easeOutBounce'
    }
  })
  .delay(1000)
  .animate({ width:400 }, 500, 'easeOutBounce');

また、イージングにはjQuery Easingプラグインを使ったイージング関数を使ってバウンドするような動きを実現しています。

面白いアニメーションの作品

forked from: jQueryアニメーションのお題 - jsdo.it - share JavaScript, HTML5 and CSS

この作品は一瞬上にコンテンツがふくらんでバウンドするような、面白い動きでページが切り替わります。また、completeオプションを使って最初のアニメーションが終わってから次の処理を行うようにしています。

$currentPage.animate({
  height: (currentHeight + tabHeight) + 'px',
  marginTop: '-' + tabHeight + 'px'
}, {
  duration: 200,
  easing: 'easeOutExpo',
  complete: function() {
      // 次の処理... 
  }
});

このようにしないと、アニメーションは並列に行われるので意図しない動作になってしまいます。

スライドするアニメーション

forked from: jQueryアニメーションのお題 - jsdo.it - share JavaScript, HTML5 and CSS

こちらはほとんど元コードの原型をとどめていない作品でした。現在の地点から距離を計算してmarginを値をアニメーションさせています。簡単にコードを解説してみたいと思います。

// タブの切り替え
function changeTab(tabId) {
  var distance;
  // コンテンツの切り替え(ここをアニメーションさせてください)
  // カレントのタブ以外を選択した場合に切り替え実行
  if($tabs.data('currentTabId') !== tabId) { // - (1)
    // 移動量算出
    distance = tabId - $tabs.data('currentTabId'); // - (2)

    // アニメーション処理
    $slider.stop(true, true);  
    $slider.animate(
      { 'marginLeft' : calcMargin(distance) }, // - (3)
      { duration : DURATION, easing : EASING_METHOD }
    );

    // カレントのタブ変更
    $tabs.data('currentTabId', tabId);    // タブID格納
    $tabs.removeClass('current');
    $tabs.filter('#tab' + tabId).addClass('current');
  }
}

この関数がタブを押したときに呼ばれる関数になっています。まず(1)の部分で、現在のタブ以外であれば実行するという条件が入っています。次に(2)の部分で現在のタブから次に表示するまでのタブの差を計算します。例えば現在のタブが1で次のタブが3なら移動量は2となります。移動量、コンテンツ1つ分の幅、現在のmarginをもと移動先のmaringの値を決める関数が以下になります。

// マージン量の算出
function calcMargin(distance) {
  var margin = parseInt($slider.css('marginLeft').replace('px', ''), 10);
  return margin + contentWidth * distance * -1;
}

後は(3)のように、このmarginの値をjQueryのanimate関数に指定すればその位置までアニメーションしてくれます。このように少し複雑なアニメーションも短いコードで書くことが可能です。

終わりに

前回と今回でjQueryのアニメーションの解説をしました。jQueryを使えば簡単にアニメーションが実装できることがわかったと思います。次回からはjQuery UIを使ったさまざまなUIの作り方について解説していきます。

おすすめ記事

記事・ニュース一覧