AngularJSのルーティング機能の基本
ルーティングとは
ルーティングとはURLに応じてコンテンツの部分を動的に表示させる仕組みです。
ルーティングは昨今話題のSinglePageApplicationを実装する上では欠かせない仕組みですが
AngularJSではこのルーティング機能を提供しており、比較的簡単に実装することができます。
ではまず今回のサンプルの完成をみてください。
ナビゲーションボタンを押すとURLが変化していき、それに合わせてコンテンツの中身だけが変わっていきますが、ページ全体が再読み込みされることがありません。
とても簡単なデモですが、ルーティング機能が実装されています。
今回のデモのファイル構成
index.html
┣ css
┃ ┗ style.css
┣script
┃ ┗ route.js(ルーティング設定)
┃ ┗ contoller.js(コントローラー設定)
┃ ┗ data.js(データ設定)
┣ view
┃ ┗ page.html(読み込み先のhtml)
index.html
まずは呼び出し元の「index.html」からです。
ソースは下記のようになります。
<!doctype html> <html lang="ja" ng-app="myApp"> <head> <meta http-equiv="Content-Type" content="text/html"; charset="UTF-8"> <script src="http://code.angularjs.org/1.4.1/angular.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-route.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.1/angular-animate.min.js"></script> <script src="script/route.js"></script> <script src="script/controller.js"></script> <script src="script/data.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css"> <link rel="stylesheet" type="text/css" href="css/style.css" /> <title>Angular Route Demo</title> </head> <body> <div> <header> <h1>Angular Route Demo</h1> <nav> <div><a href="#/girl">あかちゃん</a></div> <div><a href="#/wheel">観覧車</a></div> <div><a href="#/flower">花畑</a></div> <div><a href="#/couple">カップル</a></div> </nav> </header> <article ng-view ng-cloak class="pageContainer"></article> <footer><small>copyright(c)sample.com</small></footer> </div> </body> </html>
- ヘッダー内で、AngularJSのコアモジュールとは別に「angular-route.min.js」と「angular-animate.min.js」を読み込んでいます。それぞれルーティング機能とページ読み込みの際にアニメーションをさせるために読み込んでいます。
- ナビゲーションの各ボタンのリンク先が「#/girl」のようにハッシュを挟んでいます。
- articleタグにng-view属性を指定しており、こうすることでarticle内に別のhtmlを読み込むことができます。
script/route.js
次にroute.jsでルーティングを設定します。
angular.module('myApp',['ngRoute', 'ngAnimate']) .config(function($routeProvider){ $routeProvider .when('/girl',{ templateUrl:'views/girl.html' }) .when('/wheel',{ templateUrl:'views/wheel.html' }) .when('/flower',{ templateUrl:'views/flower.html' }) .when('/couple',{ templateUrl:'views/couple.html' }) .otherwise({ redirectTo:'/girl' }) });
モジュールを定義する際にヘッダー内で読み込んだngRouteとngAnimateを呼び出します。
angular.module('myApp',['ngRoute', 'ngAnimate'])
各URLと読み込み先の紐付けは$routeProviderを用います。ソースのルールとしては下記のようになります。
$routeProvider .when(‘特定のパス',{ templateUrl:’読み込み先のURL' }) .when(‘特定のパス',{ templateUrl:’読み込み先のURL' }) .otherwise({ //URLが上記のどれにも当てはまらない場合 redirectTo:'/girl’ //girlにリダイレクト })
css/style.css
次にCSSを見てみます。特筆すべきはこの部分です。
.pageContainer { opacity: 1; transition:all .2s linear 0s; } .pageContainer.ng-leave-active { opacity: 0; } .pageContainer.ng-enter{ opacity: 0; } .pageContainer.ng-enter-active { opacity: 0; }
ngAnimateを読み込んでいることによって、ページ読み込みの際に
ng-viewを指定したタグに下記のようなclass名がつけられます。
このクラス名を利用してcssでフェードインアニメーションをつけているわけですね。
ng-enter | 要素が追加された時(開始点) |
---|---|
ng-enter-active | 要素が追加された時(終了点) |
ng-leave | 要素が削除された時(開始点) |
ng-leave-active | 要素が削除された時(終了点) |
routeParamsサービスを使ってみる
もう少し動的にURLに応じてコンテンツを出力する仕組みにブラッシュアップしたいと思います。
script/route.js
まずroute.jsを下記のように書き換えます。
angular.module('myApp',['ngRoute', 'ngAnimate']) .config(function($routeProvider){ $routeProvider .when('/:path',{ templateUrl:'views/page.html', controller:'viewController' }) .otherwise({ redirectTo:'/girl' }) });
上記の部分で「/:path」と指定していますが、これは変数のプレイスホルダーで、今回の例で言えば
URLが「sample.com/#/girl」だった場合は「girl」が変数「path」に設定されます。
これをコントローラー側に渡します。
script/data.js
次にデータの準備をします。
通常はapiなどで取得するケースが多いと思いますが、ここでは簡易的にvalueサービスで定義します。
angular.module('myApp') .value('dataList',function(){ return { 'girl': { 'title': 'あかちゃん', 'img': 'img/girl.jpg', 'str': '赤ちゃん(あかちゃん)は、産まれたばかりの子供のこと。赤子(あかご)、赤ん坊(あかんぼう)とも言う。なお、人間以外の動物にも「赤ちゃん」が用いられることがしばしばある。種にもよるが、生存のために援助を必要とする弱い存在である。多くの種で赤ちゃんは愛らしい外見をしており、これは援助を受けやすくするために有利な形質なのではないかとの解釈もある。' }, 'wheel': { 'title': '観覧車', 'img': 'img/wheel.jpg', 'str': '観覧車の原形は、18世紀初めモスクワに登場したロシア貴族の遊具であり、あらかじめ車軸に巻き付けてあったロープを人力で引っ張るものであった。さらに17世紀には、木製の大きな輪からたらした鎖に人が乗って、この輪を人力で回すという遊具がオスマン帝国領のブルガリアにあったことが西欧からの旅行者などの記録に残っている。', }, 'flower': { 'title': '花畑', 'img': 'img/flower.jpg', 'str': '語源的には地形に由来するもの(塙→花)、歴史的背景を有するもの(寺社に花を供するための花園、また城付きの薬草園など)、近現代の開発の際に付けられたもの=単なる美称、などがある。' }, 'couple': { 'title': 'カップル', 'img': 'img/couple.jpg', 'str': 'ラテン語の「copula コプラ」という名詞や「copulare コプラーレ」という動詞に由来する。 「co」+「apere」が短縮したものであり、「co」は「一緒」、 「apere」はつなぐ、という意味[2]。つながって一緒になっているもの、という意味となったわけである。このラテン語がフランス語でcouple(クプル)となり、英語に伝わりcouple(カップル)となった。本来は、一組になったふたつ・二人全般(「一対」)を広く指している。' } }; });
script/controller.js
新たにcontroller.jsを用意します。
angular.module('myApp') //ページ用のコントローラー .controller('viewController', ['$scope','$routeParams','dataList', function($scope,$routeParams,dataList){ //パスに応じた情報をスコープに渡す var dataList = dataList(); $scope.path = $routeParams.path; $scope.title = dataList[$routeParams.path]['title']; $scope.img = dataList[$routeParams.path]['img']; $scope.str = dataList[$routeParams.path]['str']; }]);
ここでは、先ほど$routeProvider側でpathに設定した値に応じて、
dataListからコンテンツの中身(タイトル、画像、文章)をスコープに設定しています。
そしてここで設定した内容をviewで出力するわけですね。
view/page.html
読み込み先のhtmlを一つにまとめます。とてもシンプルになりました。
<div> <h2>タイトル:{{title}} パス:{{path}}</h2> <figure><img ng-src="{{img}}" alt=""></figure> <p>{{str}}</p> </div>
まとめ
とてもシンプルな例でしたが、AngularJSのルーティング機能を用いることによって
URLに応じてページの一部分だけを更新していく仕組みを実現できました。
他にも「AngularUI Router」というモジュールが用意されており、
これを使えばngRouteよりもさらに高機能なルーティングの仕組みを実装することができます。
興味のある人はそちらも触ってみてください。