どうもこんにちは。箸休め担当です。
こちらは AngularJS Advent Calendar 2014 の 22日目の投稿です。
昨年の Advent で Angular.jsで実践 アニメーション という素晴らしいまとめが発表されているのですが、
実際 jQuery でできていたものが AngularJS でどれだけ再現できるだろう?
と思って作ってみました。
今回選んだのは、jQueryの slideToggle
クリックするとびろ~んと出てくるアレです。
まずはアニメーションを付けずに Toggle の動きをさせる
class="acc-parent"
のエリアをクリックすると class="acc-child"
が表示/非表示に切り替わるという動きです。
<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>
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 ファイルを読み込ませます。
<!-- 以下のタグを追加 -->
<script src="http://code.angularjs.org/1.2.3/angular-animate.min.js"></script>
次に、モジュールの宣言箇所を以下のように修正します。
// ngAnimate を注入させる
var myApp = angular.module('myApp',['ngAnimate']);
ここまでが下準備です。
要素の表示/非表示に ngShow
を使用している場合、
非表示時に ng-hide がクラスに追加されます。(表示時は削除される)
その動きを利用して、CSS に次のような記述を入れます。
(Chromeの場合)
/* 表示・非表示切替時のアニメーション */
.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 を移動させる方法をとります。
/* 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 よりも前面に来てしまいます。
背面で移動させるために、各要素に以下のプロパティを追加します。
.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とか何とかとか)