假設一個功能畫面就像是舞台劇的一個場景的話,那麼當我們的應用程式越來越複雜時,可能會因為不同的功能而需要相對應的場景。你看喔~如果要導演本來來管理這些場景的話就太辛苦了,所以 AngularJS 提供了一個場記 $route 服務來協助我們管理這些場景。當瀏覽器指定一個網址後,$route 就依照設定來把相對應的場景及控制器一併載入。
我們先產生一個基本的模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <!doctype html> <html ng-app="OnePiece"> <head> <meta charset="UTF-8"> <title>男丁格爾's 脫殼玩 - AngularJS</title> <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css"> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0-rc.2/angular.min.js"></script> <script src="http://code.angularjs.org/1.2.0-rc.2/angular-route.min.js"></script> <script src="js/controller.js"></script> </head> <body> <div class="well span4" style="margin-top:20px;" ng-controller="OnePieceCtrl"> <h2>海賊王</h2> <div ng-view></div> </div> </body> </html> |
先來看一下基本應該要會的部份,一開始筆者指定 ng-app 的模組為 OnePiece,並指定一個控制器 OnePieceCtrl,然後放置一個空的 div 並加上 ng-view 的設定。這可以讓它當成一個容器,$route 會將符合規則的模版載入到該區塊中。
接著還有另一個需要注意的地方是,因為筆者用的 AngularJS 版本是 1.2.0,所以得額外在引用包含 ng-route 的 js 檔案才行。
準備好一個入口網頁後,接著來看我們的 OnePiece 模組:
1 2 3 4 5 6 7 8 9 10 11 12 13 | var onePiece = angular.module('OnePiece', []); onePiece.controller('OnePieceCtrl', function($scope){ $scope.friends = [{ name: '蒙其·D·魯夫', reward: 400000000 } // 略... , { name: '布魯克', reward: 33000000 }]; }); |
這邊我們產生一個很簡單 OnePiece 模組,然後 friends 是一個簡單的陣列。
筆者想要預設將 friends 的內容一一顯示在 li 中,所以得跟 $route$route 說預設為 / 是要顯示那個場景,因此得修改一下我們的模組:
1 2 3 4 5 | var onePiece = angular.module('OnePiece', ['ngRoute'], function($routeProvider){ $routeProvider.when('/', { templateUrl: 'view.html' }); }); |
雖然我們一樣是建立模組,但因為需要額外進行一些設定,所以使用的函式是 angular.module(name[, requires], configFn)。
我們在建立模組除了指定所需要的 ngRoute 模組之外,同時還多提供了一個用來設定的函式。在設定時,咱們需要幫我們準備場景的場記 $route,所以得額外傳入 $routeProvider 才行。接著使用 when(path, route) 跟場記 $route說,當遇到是 / 時,模板要從那裡來。
templateUrl 屬性是用來設定模板檔案的來源位置唷!
所以預設是希望載入 view.html,而我們的 view.html 內容就只有...:
1 2 3 | <ul> <li ng-repeat="person in friends">{{ person.name }}</li> </ul> |
這部份是接下來要請場記 $route 幫我們塞入到 ng-view 區塊中的。
好了好了,先來瀏覽一下 index.html 吧:
嘿~有看到網址後面多了一個 #/ 嗎?我們的場記 $route 會將 # 後面的內容來跟設定中的最比對,若有符合的規則就會載入指定的模板。
所以囉,請各位動手將 #/ 後面隨便輸入其它內容後按 Enter 來瀏覽,應該就只會看到我們的標題而已:
讓我們再多練習一下,新增一個 edit.html 用來編輯某一筆資料:
1 2 3 4 5 | <label>姓名:</label> <input type="text" ng-model="friends[0].name"> <label>懸賞金:</label> <input type="text" ng-model="friends[0].reward"> |
筆者希望到瀏覽到 /edit 時就顯示這個場景,預設就是編輯陣列中的第一筆資料,所以再來跟場記 $route 說明一下規則吧:
1 2 3 4 5 | $routeProvider.when('/', { templateUrl: 'view.html' }).when('/edit', { templateUrl: 'edit.html' }); |
來手動將網址改成 /edit 後就會看到:
不過,我們就只有兩個場景,但若是使用者輸入的網址不符合這兩個場景的規則的話,那不就都看到錯的內容嗎?
好在場記 $route它除了設定換景規則之外,它還能透過 otherwise(params) 來設定若不符合以上全部規則的話,就預設顯示那個模板。
1 2 3 4 5 6 7 | $routeProvider.when('/', { templateUrl: 'view.html' }).when('/edit', { templateUrl: 'edit.html' }).otherwise({ redirectTo: '/' }); |
透過 redirectTo 屬性可以強迫載入指定的場景模板。因此只要使用者輸入的網址不在規則中的話,都是被轉到 #/ 並看到 view.html 的內容:
請各位先試試看剛剛的 otherwise(params) 效果,並新增一個場景為 /hello,然後內容就是跟你喜歡的角色說聲 "Hi"。
看到这样的一种写法,和您的不一样,但是也有效果。
angular.module('block1', []).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/pt1', { templateUrl: 'partial1.html' });
$routeProvider.when('/pt2', { templateUrl: 'partial2.html' });
$routeProvider.otherwise({ redirectTo: '/pt2' });
}]);