Quantcast
Channel: アシアルブログ
Viewing all articles
Browse latest Browse all 298

即興で自分のランチ行きつけのお店をAngularJSを使ってアプリっぽくしてみる

$
0
0
大塔です。今回は1日の業務時間の空き時間を使ってAngularJSの機能を使って即興で行きつけのお店AngularJSを使ってアプリっぽくしてみました。あまり時間をかけられなかったため、かなり荒削りで恥ずかしい部分もありますが、AngularJSの機能をこれで紹介できればと思います。Directive,ngIncludeについて紹介します。なお、画像はお店の方の了承をいただいて使っています。4つのアイコンはクリックできますが、タブバーには何のイベントも設定していないので、ただの飾りです。




ディレクトリ構造は以下の図のようになっています。


index.html

  1. <!doctype html>
  2. <html ng-app="MonaApp">
  3.   <head>
  4.     <meta charset="UTF-8"/>
  5.     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  6.     <link rel="stylesheet" href="css/normalize.css"/>
  7.     <link rel="stylesheet" href="css/font-awesome.min.css"/>
  8.     <link rel="stylesheet" type="text/css" href="css/style.css" />
  9.     <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
  10.     <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular-animate.min.js"></script>
  11.     <script type="text/javascript" src="js/app.js"></script>
  12.  </head>
  13.  <body>
  14.     <div ng-controller="MonaCtrl">
  15.         <my-header></my-header>
  16.             <my-container></my-container>
  17.         <my-footter></my-footter>
  18.     </div>
  19.  </body>
  20. </html>

app.js

  1. var MonaApp = angular.module('MonaApp', ['ngAnimate'])
  2.     
  3.     .directive('myHeader', function() {
  4.         return {
  5.             restrict: "E",
  6.             templateUrl: 'templates/header.html'
  7.         };
  8.     })
  9.     
  10.     .directive('myContainer', function() {
  11.         return {
  12.             restrict: "E",
  13.             templateUrl: 'templates/container.html'
  14.         };
  15.     })    
  16.     .directive('myFootter', function() {
  17.         return {
  18.             restrict: "E",
  19.             templateUrl: 'templates/footer.html'
  20.         };
  21.     });
  22.     
  23.  
  24.  
  25.     function MonaCtrl($scope) {
  26.         $scope.templates =
  27.     [ 
  28.       { name: 'navigator.html', url: 'templates/navigator.html'},
  29.       { name: 'info.html', url: 'templates/info.html'},
  30.       { name: 'map.html', url: 'templates/map.html'},
  31.       { name: 'diet.html', url: 'templates/diet.html'},
  32.       { name: 'flower.html', url: 'templates/flower.html'}
  33.     ];
  34.  
  35.     $scope.changePage = function(page, isback){
  36.         
  37.         if (typeof isback !== "undefined" && isback !== null) {
  38.                 $scope.isBack = isback;
  39.         }        
  40.         
  41.         switch (page) {
  42.             case "home":
  43.                 $scope.template = $scope.templates[0];
  44.             break;
  45.             
  46.             case "info":
  47.                 $scope.template = $scope.templates[1];
  48.             break;
  49.             
  50.             case "map":
  51.                 $scope.template = $scope.templates[2];
  52.             break;
  53.             
  54.             case "diet":
  55.                 $scope.template = $scope.templates[3];
  56.             break;
  57.             
  58.             case "flower":
  59.                 $scope.template = $scope.templates[4];
  60.             break;               
  61.         }
  62.     }
  63.  
  64.     $scope.template = $scope.templates[0];
  65. }


Directive



まず、見慣れないタグがindex.htmlを見ていると飛び込んでくると思います。$ltbody&gtにはこの3つのタグと全体を囲うdivタグしか記述されていないことが見て取れると思います。

  1. ....
  2.  
  3.         <my-header></my-header>
  4.             <my-container></my-container>
  5.         <my-footter></my-footter>
  6. ....

「ん???....こんなHTMLタグ見たことないぞ?」と思われかもしれません。AngularJSを触っている方はご存知かと思いますが、AngularJSではDirectiveという機能を使って自分でhtmlタグを作成することができます。このタグを定義している部分を見てみましょう。app.jsで定義してあります。


  1. var MonaApp = angular.module('MonaApp', ['ngAnimate'])
  2.     .directive('myHeader', function() {
  3.         return {
  4.             restrict: "E",
  5.             templateUrl: 'templates/header.html'
  6.         };
  7.     })
  8.     
  9.     .directive('myContainer', function() {
  10.         return {
  11.             restrict: "E",
  12.             templateUrl: 'templates/container.html'
  13.         };
  14.     })    
  15.     .directive('myFootter', function() {
  16.         return {
  17.             restrict: "E",
  18.             templateUrl: 'templates/footer.html'
  19.         };
  20.     });


  1. var MonaApp = angular.module('MonaApp', ['ngAnimate'])

上記の記述はngAnimateというモジュールを読み込んでMonaAppというモジュールを新たに定義するという趣旨の記述です。ここに数珠つなぎのように.directive()でチェーンして、ディレクティブを定義しています。MonaAppというのは私が勝手に定義したモジュールです。index.htmlの冒頭でng-app=MonaAppという記述を行い、MonaAppを適用しています。

  1. <html ng-app="MonaApp">

このMonaAppに属するディレクティブとして、&ltmy-header&gt、&ltmy-container&gt、&ltmy-footter&gtという3つのディレクティブを定義しています。参考として&ltmy-header&gtを見てみましょう。

  1. .directive('myHeader', function() {
  2.         return {
  3.             restrict: "E",
  4.             templateUrl: 'templates/header.html'
  5.         };
  6.     })

AngularJSで定義したmyHeaderというディレクティブを実際にhtmlに記述する場合はmy-headerとなることに注意してください。第1引数でディレクティブ名を、第2引数でオブジェクトを戻り値として返す関数を定義しています。


中を見ていきましょう。

restrictはこのディレクティブをどのような形でhtml中で用いるかを定義するプロパティです。ここではE (Element) 、すなわちhtmlの要素、タグとして、ディレクティブを用いることを定義しています。他にもrestrict:Aとして&ltdiv my-header&gt&lt/div&gthtmlの属性 (Attribute) としてディレクティブを用いることができるように定義したり、色々な形でディレクティブを定義することができます。

templateUrlにはそのディレクティブ中で読み込むテンプレートのURLを定義します。ここではテンプレートとしてtemplates/header.htmlを指定しています。

実際にtemplates/header.htmlを見てみましょう。

  1. <div class="header">
  2.     <a ng-click="changePage('home', false)" ng-show="isBack"><i class="fa fa-chevron-circle-left"></i></a><p ng-show="!isBack">Florist KT</p>
  3. </div>

この上記のHTMLがindex.html中の&ltmy-header&gt&lt/my-header&gtという記述一行で読み込まれることになります。1つのファイル中のhtmlの記述が増えてくると、ごちゃごちゃして見にくくなってくる経験があると思います。AngularJSではディレクティブという機能を提供することによって、htmlをコンポーネントごとに分割できるようになっています。コンポーネントを作る以外にもdirectiveには様々なことができますので、是非、興味のある方は調べてみてください。


ngInclude



次に、ngIncludeについて紹介します。ngIncludeを用いることで動的に読み込むテンプレートを変更することができます。まずは&ltmy-container&gtで読み込んでいるtemplates/container.htmlを見てみましょう。


  1. <div class="slide-animate-container" id="content">
  2.     <div id="animation" class="slide-animate" ng-include="template.url" ></div>
  3. </div>


ngIncludeを使ったことのない方はng-includeという見慣れない属性があることが見て取れると思います。ここではng-includeでtemplate.urlを指定しています。app.jsを見てみましょう。

  1. function MonaCtrl($scope) {
  2.  
  3.     $scope.templates =
  4.       [ 
  5.       { name: 'navigator.html', url: 'templates/navigator.html'},
  6.       { name: 'info.html', url: 'templates/info.html'},
  7.       { name: 'map.html', url: 'templates/map.html'},
  8.       { name: 'diet.html', url: 'templates/diet.html'},
  9.       { name: 'flower.html', url: 'templates/flower.html'}
  10.       ];
  11.  
  12.     ...
  13.  
  14.     $scope.template = $scope.templates[0];

ng-include="template"は上記の最下部の$scope.templateを参照しています。上記のコードを見ると$scope.templateには$scope.templates[0]、すなわち{ name: 'navigator.html', url: 'templates/navigator.html'}が代入されています。このオブジェクトのurlの部分、すなわち'templates/navigator.html'ng-include="template.url"という記述で読み込まれます。

このng-includeで読み込まれるhtmlテンプレートであるtemplates/navigator.htmlは下記のように記述されています。


  1. <ul id ="category">
  2.     <li ng-click="changePage('info', true)"><img class="listedImages" src="images/appearance2.png"><h3>お店について</h3><p>こだわりのお食事やお茶、お菓子、お酒もご提供しています。</p></li>
  3.     <li ng-click="changePage('diet', true)"><img class="listedImages" src="images/diet.png"><h3>お食事</h3><p>お花屋と飲食が一緒になった東京でも珍しい形のお店です!</p></li>
  4.     <li ng-click="changePage('flower', true)"><img class="listedImages" src="images/flower.png"><h3>お花</h3><p>多種多様な東京一力のある元気な花、植木を取りそろえております。
  5.     </p></li>
  6.     <li ng-click="changePage('map', true)"><img class="listedImages" src="images/sign.png"><h3>アクセス</h3><p>お店の場所です。</p></li>
  7. </ul>

ちょっと変な書き方ですが、4つの&ltli&gtタグにngClickという属性を指定しています。そのng-clickにはchangePage()という関数を定義しています。changePage()を定義しているapp.jsを見てみましょう。

  1. $scope.changePage = function(page, isback){
  2.         
  3.         if (typeof isback !== "undefined" && isback !== null) {
  4.                 $scope.isBack = isback;
  5.         }        
  6.         
  7.         switch (page) {
  8.             case "home":
  9.                 $scope.template = $scope.templates[0];
  10.             break;
  11.             
  12.             case "info":
  13.                 $scope.template = $scope.templates[1];
  14.             break;
  15.             
  16.             case "map":
  17.                 $scope.template = $scope.templates[2];
  18.             break;
  19.             
  20.             case "diet":
  21.                 $scope.template = $scope.templates[3];
  22.             break;
  23.             
  24.             case "flower":
  25.                 $scope.template = $scope.templates[4];
  26.             break;               
  27.         }
  28.     }


ng-click="changePage()"app.js$scope.changePage()を参照します。changePage()関数は第1引数として、遷移先のページを表す文字列を受け取ります。そして、その文字列に対応して$scope.templateの値を切り替えています。すなわち、&ltli ng-click="changePage()"&gtというタグをクリック、タップした時に対応するページにtemplates/container.html&ltdiv id="animation" class="slide-animate" ng-include="template.url" &gt&lt/div&gtは切り替わります。このようにngIncludeを用いることで動的にテンプレートを切り替えることができます。


ngAnimate



&ltli&gtをクリックした際にアニメーションをしながらページが切り替わると思います。もう一度、templates/container.htmlを見てみましょう。


  1. <div class="slide-animate-container" id="content">
  2.     <div id="animation" class="slide-animate" ng-include="template.url" ></div>
  3. </div>

ng-include属性が定義してあるdivタグに"slide-animate"というCSSクラスが適用されているのが見て取れると思います。ngIncludeは自分にかけられているCSSのクラスを自動的に探して、そのCSSをページの切り替わり時に反映します。style.cssにこれらのクラスが定義してあるので見てみましょう。


  1. .slide-animate-container {  
  2.   position:relative;
  3.   height:568px;
  4.   width : 100%;
  5.   overflow:hidden;
  6. }
  7.  
  8. .slide-animate.ng-enter, .slide-animate.ng-leave {
  9.   -webkit-transition-duration: 0.43s;
  10.   position:absolute;
  11.   display:block;
  12. }
  13.  
  14. .slide-animate.ng-enter {
  15.     -webkit-transform: translate3d(120%,0px,0px);
  16. }
  17. .slide-animate.ng-enter.ng-enter-active {
  18.     -webkit-transform: translate3d(0px,0px,0px);
  19. }
  20.  
  21. .slide-animate.ng-leave {
  22.     -webkit-transform: translate3d(0px,0px,0px);
  23. }
  24. .slide-animate.ng-leave.ng-leave-active {
  25.     -webkit-transform: translate3d(120%,0px,0px);
  26. }

上記のCSSクラスの内

新しく入ってくるテンプレート (新しい画面) に対しては.ng-enter.ng-enter-activeがCSSとして追加されます。追加されたCSSはアニメーション完了後に削除されます。画面から消えるテンプレート (元の画面) に対しては.ng-leaveng-leave-activeがCSSとして要素に追加されます。追加されたCSSはアニメーション完了後に削除されます。ここでは新しく入ってくる画面は画面の右端からアニメーションをしながら入ってきて、元の画面は今ある位置から画面右にスライドしながら消えていくCSSを適用しています。それぞれのアニメーションの秒数は0.43秒に設定しています。考え方がちょっと特殊なので、慣れるまでは使いこなすのが大変かと思いますが (自分もまだ使いこなせていません) アニメーションをかける関数などを用意しなくて良いので、その点では便利だと思います。ngAnimateに関してはこのブログが詳しいので、興味のある方はこちらを参照してみてください。


まったくもって完全に余談なのですが、ここのお店のランチセット(餃子、カレー、ハンバーグ)などはかなりおいしいです。近所に寄った時は是非ご賞味ください!!!

Viewing all articles
Browse latest Browse all 298

Trending Articles