【BiTT】俺のクローン作るしかなくね!?
【BiTT】俺のクローン作るしかなくね!?
2015.06.23

AngularJSでマテリアルデザイン風のページ遷移アニメーションを作ろう

先生

index.html

はじめに、index.htmlを書きましょう。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.96.1/css/materialize.min.css"/>
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body ng-app="app">
        <nav>
            <div class="nav-wrapper">
                <a ui-sref="/" class="brand-logo">Sample</a>
            </div>
        </nav>
        <div class="view-container">
          <div ui-view class="view"></div>
        </div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0/angular.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0/angular-animate.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
        <script src="js/app.js"></script>
    </body>

</html>

おそらく説明不要なほどシンプルなものだと思います。
必要なangular,angular-animte,ui-routerと、これから作るapp.jsを読み込んでおきます。

app.js

つづいて、app.jsを書いていきましょう。

(function (angular) {
    // メンバー情報を配列にいれておく
    var MEMBERS = [
        {
            id: 1,
            name: "おじいちゃん",
            description: "フロントエンドエンジニアのおじいちゃんと言います。本当は24歳です。よろしくお願いします。"
        },
        {
            id: 2,
            name: "はやち",
            description: "フロントエンドエンジニアのはやちです( ˘ω˘)☝以前までは顔隠しておりましたが思い切ることにしました…。相変わらず顔文字乱舞ですがブログもコーディングも楽しくやっていこうと思います✌(´ʘ‿ʘ`)✌Androidの方は相変わらず文字化けすいません(◞‸◟)"
        },
        {
            id: 3,
            name: "先生",
            description: "フロントエンドエンジニアの林です。業務効率化するアプリが大好き。AngularJS好きのJavaScripter。ディレクション・サーバーサイド開発・デザインにもぐいぐい入り込んでいきます。あとテニスが好きです。"
        },
        {
            id: 4,
            name: "せいと",
            description: "最近フロントエンドエンジニアになりました。第一回HTML5カルタ大会で優勝しました。休日の過ごし方は、\"Jazz Barでスコッチを片手に『世界の終りとハードボイルド・ワンダーランド』を読む\"です。"
        },
        {
            id: 5,
            name: "まろC",
            description: "フロントエンドエンジニアのまろCです。最近はAWSもやってCMSも構築して、手タレもやっています。"
        },
        {
            id: 6,
            name: "いなば",
            description: "フロントエンドエンジニアの稲葉です。Web制作→ソーシャルゲーム開発を経てまたWeb制作に戻ってきました。趣味はランニングと一眼レフです。TRIPに続くWebサービスの立ち上げに参加する事と東京マラソン出場&完走が密かな目標です。"
        },
        {
            id: 7,
            name: "店長",
            description: "ロントエンドエンジニアの店長です。LIGに入社と同時に店長(あだ名が)になりました。偉くはありません。以前、某カフェで働いていました。音楽とコーヒーが大好きです。よろしくお願いいたします。"
        }
    ];
    // ngAnimateとui.routerモジュールを使う
    angular.module('app', ['ngAnimate', 'ui.router'])
        .config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
            // 以下ルーティングの設定
            $urlRouterProvider.otherwise("/");
            $stateProvider
                .state('/', {
                    url: "/",
                    controller: 'HomeController as home',
                    templateUrl: "home.html"
                }).state('profile', {
                    url: '/profile/:id',
                    templateUrl: 'profile.html',
                    controller: 'ProfileController as profile'
                });
        }])
        // 最初のページ
        .controller('HomeController', [function () {
            this.members = MEMBERS;
        }])
        // プロフィールページ
        .controller('ProfileController', ['$stateParams', function ($stateParams) {
            var index = parseInt($stateParams.id, 10);
            this.member = MEMBERS[index - 1];
        }]);

})(angular);

MEMBERSという変数にメンバーの情報を格納しています。
configでui-routerの設定をしています。ui-routerの使い方は公式のドキュメントをご覧ください。

https://github.com/angular-ui/ui-router

コントローラーはあまり処理をおこなっていません。
ProfileControllerではパラメータでもらったID番号を元に、メンバーのデータ1件を取得しているだけです。

home.html

つづいて最初のページ(home.html)を作ります。

<ul class="collection">
    <li class="collection-item avatar" ng-repeat="member in home.members" ui-sref="profile({id:member.id})">
        <!-- サムネイル -->
        <img ng-src="./images/{{member.id}}.jpg" alt="" class="circle thumb"
             ng-animate-ref="thumb-{{ member.id }}" width="60" height="60">
        <!-- 名前 -->
        <div class="name" ng-animate-ref="title-{{ member.id }}">{{member.name}}</div>
        <!-- 影付きの枠をアニメーションさせるための空要素 -->
        <div class="z-depth-1" ng-animate-ref="shadow-{{member.id}}"></div>
    </li>
</ul>

ng-repeatで繰り返しをするので、ng-animate-refにもIDを付けて一意の値にします。
ng-animate-ref=”thumb-{{ member.id }} この部分が重要です。
今回はIDを連番にしているのでthumb-1,thumb-2と出力されていきます。

profile.html

さらにプロフィールページ(profile.html)を作ります。

<div class="row profile-container">
    <div class="col s8 offset-s2">
        <!-- 影付きの枠 -->
        <div class="z-depth-1 profile shadow" ng-animate-ref="shadow-{{profile.member.id}}">
            <div>
                <!-- サムネイル -->
                <img ng-src="./images/{{profile.member.id}}.jpg" alt="" class="profile circle thumb"
                     ng-animate-ref="thumb-{{ profile.member.id }}" width="80" height="80">
                <!-- 名前 -->
                <div class="profile name" ng-animate-ref="title-{{ profile.member.id }}">{{ profile.member.name }}</div>
            </div>
            <!-- 説明文 -->
            <div>
                {{profile.member.description}}
            </div>
        </div>
        <!-- 戻るボタン -->
        <a ui-sref="/" class="waves-effect waves-light btn"><i class="mdi-navigation-arrow-back left"></i>戻る</a>
    </div>
</div>

プロフィールページではmemberにクリックされたメンバーの情報が格納されています。こちらのng-animate-refは、home.htmlについているのと同じ値になるようにしておきます。

<img ng-animate-ref="thumb-{{ profile.member.id }}"

上記のようにしておけば、thumb-1やthumb-2などとなります。