LoginSignup
18
17

More than 5 years have passed since last update.

ngAnimateを使ってjQueryのslideToggleちっくなものを作ってみた

Posted at

どうもこんにちは。箸休め担当です。
こちらは AngularJS Advent Calendar 2014 の 22日目の投稿です。

昨年の Advent で Angular.jsで実践 アニメーション という素晴らしいまとめが発表されているのですが、
実際 jQuery でできていたものが AngularJS でどれだけ再現できるだろう?
と思って作ってみました。

今回選んだのは、jQueryの slideToggle
クリックするとびろ~んと出てくるアレです。

まずはアニメーションを付けずに Toggle の動きをさせる

class="acc-parent" のエリアをクリックすると class="acc-child" が表示/非表示に切り替わるという動きです。

sample.html
<div ng-app="myApp">
    <div class="accordion-contain" ng-controller="accordionCtrl">
        <div class="acc-parent" ng-click="accOpen()">Test title</div>
        <div class="acc-child" ng-show="bodyShow">Test body</div>
    </div>
</div>
sample.js
var myApp = angular.module('myApp',[]);

myApp.controller('accordionCtrl',['$scope', function($scope){
    // ロード時 "acc-child" は非表示
    $scope.bodyShow = false;
    $scope.accOpen = function(){
        // bodyShowをtrue/falseにすることで表示の切り替えを行う
        $scope.bodyShow = !$scope.bodyShow;
    };
}]);

この時点で CSS は背景や文字の色付けにしか使わないので省略。

デモは こちら
パカパカ開くようになりました。

ngAnimate を注入して動きをつける

こちらを参考に動きをつけてみます。
AngularJSのアニメーションの仕組みについて

まずはアニメーション用の js ファイルを読み込ませます。

sample.html
<!-- 以下のタグを追加 -->
<script src="http://code.angularjs.org/1.2.3/angular-animate.min.js"></script>

次に、モジュールの宣言箇所を以下のように修正します。

sample.js
// ngAnimate を注入させる
var myApp = angular.module('myApp',['ngAnimate']);

ここまでが下準備です。

要素の表示/非表示に ngShow を使用している場合、
非表示時に ng-hide がクラスに追加されます。(表示時は削除される)
その動きを利用して、CSS に次のような記述を入れます。
(Chromeの場合)

sample.css
/* 表示・非表示切替時のアニメーション */
.acc-child.ng-hide-add,
.acc-child.ng-hide-remove{

    /* 全ての要素を、一定の速度で、1秒間表現する */
    -webkit-transition:all linear 1s;

    /* アニメーション実行前に非表示にされるのを回避 */
    display:block!important;
}

/* acc-child 非表示 */
/* ng-hide が追加されたときに適用される */
.acc-child.ng-hide-add.ng-hide-add-active,
.acc-child.ng-hide-remove {
    opacity:0;
}

/* acc-child 表示 */
/* ng-hide が削除されたときに適用される */
.acc-child.ng-hide-remove.ng-hide-remove-active,
.acc-child.ng-hide-add {
    opacity:1;
}

opacity で要素の透明度を指定します。
ng-hideが追加されたときには opacity が 1 (不透明) → 0 (透明) へ、
削除されたときは 0 → 1 へとアニメーションが実行されるという指定です。

デモは こちら
ふわ~っと表示されるようになりました。
ただ、僕がやりたいのはこれじゃない。ふわ~じゃなくて、びろ~んです。

より slideToggle らしい動作へ

ここからは CSS の話です。

先程 opacity プロパティを使用し透明度に変化をつける話をしました。
つまり、この部分を opacity 以外のもので変化させれば
slideToggle 風の動きが実現できそうですね。

今回は transform: translate(x, y) で acc-child を移動させる方法をとります。

sample.css
/* acc-child非表示 */
/* ng-hideが追加されたときに適用される */
.acc-child.ng-hide-add.ng-hide-add-active,
.acc-child.ng-hide-remove {
    -webkit-transform:translate(0px,-36px);
}

/* acc-child表示 */
/* ng-hideが削除されたときに適用される */
.acc-child.ng-hide-remove.ng-hide-remove-active,
.acc-child.ng-hide-add {
    -webkit-transform:translate(0px,0px);
}

class="acc-parent"class="acc-child" ともに縦の幅が 36px のため、
Y軸方向に 36px 分移動するよう指定しました。
非表示時、acc-child は acc-parent に重なるため、マイナス幅の移動になります。

ただ、このままで動作すると acc-child が acc-parent よりも前面に来てしまいます。
背面で移動させるために、各要素に以下のプロパティを追加します。

sample.css
.acc-parent {
    background: hsl(90, 60%, 70%);
    color: hsl(90, 30%, 30%);
    padding: 10px;
    /* acc-parentが必ず前面に来るように設定 */
    position: relative;
    z-index:1;
}

.acc-child {
    background: hsl(100, 80%, 90%);
    color: hsl(90, 30%, 30%);
    padding: 10px;
    /* acc-parentが必ず前面に来るように設定 */
    position: relative;
    z-index:0;
}

z-index で要素の重なりの順番を指定します。(この場合、値の大きいacc-parent の方が前面)
また、z-index を指定する場合は position: static; 以外 の指定が必要になるため、
position: relative; も指定してあげます。

デモは こちら

slideToggle らしくなりましたね!!

その他参考にしたページ

How to create an accordion with AngularJS
(最初はアコーディオンを作る予定だったので。。。)
Stack Overflow - Slide up/down effect with ng-show and ng-animate
CSS3 アニメーション(Transitions)の使用方法
CSS3 変形処理を行う transform プロパティ
要素の重なりについて本気出して考えてみた(z-indexとか何とかとか)

18
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17