Web制作
AngularJS ui-routerを使って認証機能を実装してみよう
みなさま、GWは満喫できたでしょうか? こんにちは、フロントエンドエンジニアの稲葉です。 今回はAngularJSでui-routerを使って簡単に認証機能を実装したサンプルをご紹介したいと思います。 実際の動作はDEMOで確認することがで[…]
こんにちは。
6月から役職が変わりフロントエンドリーダーからCTOになりました、先生です。
もうAngular1.4にアップデートしましたか? Angular1.4になりマテリアルデザインを意識したアニメーション関連の変更や実装がおこなわれました。その分Breaking Changesもあるのでアップデートには注意する必要があります。
今日はそんなAngularJS 1.4を使って、マテリアルデザイン風にページ遷移するアニメーションを作ってみたいと思います。
▼目次
デモは下記リンクになります。
各メンバーをクリックするとスムーズにアニメーションして詳細ページに遷移します。まずは触ってみてください。
http://frontainer.com/ligblog-sample/angular-morphing-animation/#/
Angular Routerでも機能しますが、今回はよく使われているUI Routerを使用します。
また、Materializeは見た目をマテリアルデザイン風にしてくれるフレームワークで、今回はスタイルだけを使用します。
Angular Animate1.4でAnimation Anchoringという機能が追加されました。
これを使うことで、遷移前と後の同じ要素をアニメーションさせながら画面を切り替えることができます。
使い方は簡単で、紐付けたい要素に同じ値のng-animate-ref属性を付け、CSSでtransitionを設定してあげるだけです。
<!-- ページA --> <span class="page-a dummy" ng-animate-ref="hoge">dummy text</span> <!-- ページB --> <span class="page-b dummy" ng-animate-ref="hoge">dummy text</span> <!-- css --> } .dummy-anchor-in { transition: 0.5s ease-out all; }
Angular記法で変数を指定してもOKです。
<span class="page-a dummy" ng-animate-ref="{{myValue}}">dummy text</span>
ng-animate-refに関しては、下記の公式ページに記載があります。
https://docs.angularjs.org/api/ngAnimate#animation-anchoring-via-ng-animate-ref-
デモのコードはGithubで公開していますので、そちらもご覧ください。
https://github.com/frontainer/ligblog-sample/tree/master/angular-morphing-animation
構成は下図のとおり。
index.html home.html profile.html ┣ css/ ┃ ┗ style.css ┣ js/ ┃ ┗ app.js ┗ images/ ┗ *.jpg
はじめに、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を書いていきましょう。
(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)を作ります。
<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)を作ります。
<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などとなります。
最後にCSSを作りアニメーションの設定をおこないます。
.view-container { position: relative; } .view.ng-animate { position: absolute; top: 0; left: 0; width: 100%; min-height: 500px; } .view.ng-enter, .view.ng-leave { transition: 0.5s cubic-bezier(.55,0,.1,1) all; } .view.ng-enter { opacity: 0; } .view.ng-enter.ng-enter-active, .view.ng-leave { opacity: 1; } .view.ng-leave.ng-leave-active { opacity: 0; } .name.ng-anchor-in, .thumb.ng-anchor-in,.shadow.ng-anchor-in { transition: 0.5s cubic-bezier(.55,0,.1,1) all; } .profile.shadow { padding: 20px; } .profile.name { font-size: 24px; font-weight: bold; } .profile-container { padding: 20px; margin: 20px; }
.view関連はページ遷移をフェードで切り替えるためのものです。
ng-anchor-inというのが記述に追加されています。ここにtransitionの設定を記述します。
こうして作ったのが先ほどのデモになります。
このように遷移前と後のng-animate-refにつけた名称と一致するものが、アニメーションして切り替わるようになります。複雑そうに見えるアニメーションが簡単に実装できてしまいました。
http://frontainer.com/ligblog-sample/angular-morphing-animation/#/
諸事情により1.4に上げるのが難しい場合は「Angular-Hero」というモジュールがあります。これを使うと1.3でも同様のアニメーションを実装することができます。
Angular-Heroは1.4だとページ遷移のアニメーションが動作しなかったため、修正したものをプルリクエストしマージされています。そのため、1.3で作った後に1.4にあげても変わらず動作するようになりました。(バージョン0.0.7)
app.jsを非同期読み込みにするためにasync属性を付けてangular.bootstrapで初期化していると、ng-animate-refによるアニメーションが正しく動作しませんでした。
JSエラーが出て動作しないなぁと思ったら下記を確認してみてください。(これは本当にわからなかった)
<script src="app.js" async></script>
app.js
angular.bootstrap(document, ["app"], { strictDi: true });
Angular Animate1.4はBreaking Changesがあるので、1.3でアニメーションをガンガン使っている場合にはアップデートに注意が必要です。
しかし、1.4はパフォーマンスの改善だけでなくアニメーションについても強力で魅力的なものになっているので、制限がなければバージョンアップしてみてはいかがでしょうか。
【関連リンク】
Web制作
AngularJS ui-routerを使って認証機能を実装してみよう
みなさま、GWは満喫できたでしょうか? こんにちは、フロントエンドエンジニアの稲葉です。 今回はAngularJSでui-routerを使って簡単に認証機能を実装したサンプルをご紹介したいと思います。 実際の動作はDEMOで確認することがで[…]
Web制作
AngularJSのngResourceモジュールをRestangularに置き換えてみた
こんにちは、フロントエンドエンジニアのいなばです。 最近引っ越して台東区民になりました。憧れだったチャリ通勤ができてとても満足しています。 今回はAngularJSで開発している案件で、Ajax通信部分をngResourceからRestangularに[…]
Web制作
AngularJSのOne-time Bindingを使ってパフォーマンス改善をしよう
こんにちは。 先日ng-japanにスポンサー企業として参加してきました、先生です。 本日は、すごくマジメに資料を作ったのに爆笑に包まれてしまったLTで発表した内容を、整理してお送りします。なぜ爆笑されたかについてはここでは語[…]