
AngularJS 路由機制是由ngRoute模塊提供,它允許我們將視圖分解成布局和模板視圖,根據url變化動態的將模板視圖加載到布局中,從而實現單頁面應用的頁面跳轉功能。
AngularJS 路由允許我們通過不同的 URL 訪問不同的內容。
通過 AngularJS 可以實現多視圖的單頁Web應用(single page web application,SPA)。
通常我們的URL形式為 http://cnblogs.com/first/page,但在單頁Web應用中 AngularJS 通過 # + 標記 實現,例如:
http://cnblogs.com/#/first
http://cnblogs.com/#/second
http://cnblogs.com/#/third
當我們點擊以上的任意一個鏈接時,向服務端請的地址都是一樣的 (http:/cnblogs.com/)。 因為 # 號之后的內容在向服務端請求時會被瀏覽器忽略掉。 所以我們就需要在客戶端實現 # 號后面內容的功能實現。 AngularJS 路由 就通過 # + 標記 幫助我們區分不同的邏輯頁面並將不同的頁面綁定到對應的控制器上。

01
路由使用
① 引入文件並注入依賴
<script src="angular-route.min.js"></script> var app = angular.module("myApp",['ngRoute']);
② 創建一個布局模板
之所以要創建布局模板,是為了告訴AngularJS應該將布局渲染到何處。通過ng-view指令,我們可以精確的指定模板視圖在DOM中的渲染位置。
<div ng-app="myApp"> <a ng-href="#/bq1">標簽1</a> <a ng-href="#/bq2">標簽2</a> <a ng-href="#/bq3">標簽3</a> <a ng-href="#/bq4">標簽4</a> <div ng-view></div> </div>
③ 創建一些模板視圖
myBq1.html
<p>這是標簽1</p>
myBq2.html
<p>這是標簽2</p>
myBq3.html
<p>這是標簽3</p>
myBq4.html
<p>這是標簽4</p>
④ 定義路由表
app.config(['$routeProvider',function($routeProvide) { $routeProvide .when('/',{templateUrl:"home.html"}) .when('/music',{templateUrl:"myMusic.html"}) .when('/movie',{templateUrl:"myMovie.html"}) .when('/novel',{templateUrl:"myNovel.html"}) .otherwise({redirectTo:'/'}); }]);
02
深入路由
① 涉及到的服務與指令
- $routeProvider 用來定義路由表,我們會用到里面的when和otherwise兩個方法。
- $routeParams 用來保存地址欄中的參數,也提供了通配某類地址的能力。
- $location 用來分析處理url。
- $ng-view 用來指定加載模板視圖的區域。
② $location.path()詳解
如果沒有參數,返回當前路徑,即#號后的內容;也可以傳入字符串,將當前路徑修改為字符串的內容,並觸發路由變化。
假設當前url:http://localhost:63342/RouteDemo/index.html#/
//返回'/'
$location.path();
//將當前url修改為:http://localhost:63342/RouteDemo/index.html#/music
$locaiton.path('/music');
//返回'/music'
$locaiton.path();
③ when及otherwise詳解
when方法能夠接收兩個參數,第一個參數是路由路徑,這個路徑會與$location.path()的值進行匹配,如果沒有任何一個when方法匹配到,那么將會執行otherwise方法。第二個參數是配置對象,它的六個屬性分別是controller,template,templateUrl,resolve,redirectTo,reloadOnSearch。
- controller
該屬性值可以是一個字符串,也可以是一個函數。如果是字符型,則會搜索相應的控制器,如果是函數,那么該函數代表控制器(可以用controllerAs為控制器命名或起別名)。控制器會與路由所創建的作用域關聯在一起,並且轉到該路徑時都會執行一次控制器中的內容。
//每次路徑變為/music觸發路由變化時都會執行一次控制器中的內容 app.config(['$routeProvider',function($routeProvide) { $routeProvide.when('/music'{templateUrl:"myMusic.html",controller:"myController"}) }]); app.controller('myController',function($scope) { console.log("123"); });
- controllerAs
給controller屬性值代表的控制器起個別名,以便之后引用。 - template
值是一個字符串,代表一個Html模板,AngularJS會拿該模板來渲染。 - templateUrl
值是一個字符串,代表一個存着Html模板的路徑,AngularJS會拿該路徑下的Html模板來渲染。 - resolve
值是一個對象,該對象屬性名是可以注入到控制器的依賴,屬性值可包含下列內容。
只有當resolve對象里所有promise對象執行完畢后才會注入到控制器,此時才會發生路由變化,因此可以解決頁面閃爍問題(加載頁面后才獲取到數據去更新視圖)。我們來看看對比,下面這個例子控制器注入的a是自定義的myService服務,注入的b則是從服務器端獲取到的數據。
test.html代碼如下。
<p>我是測試界面 {{ name }}</p> <div ng-repeat="name in list">{{ name }}</div>
index.html代碼如下。
<body ng-app="myApp"> <div ng-app="myApp"> <a ng-href="#/test">測試</a> <div ng-view></div> </div> <script> var app = angular.module("myApp",['ngRoute']); app.value("myService","張三"); app.config(['$routeProvider',function($routeProvide) { $routeProvide .when('/test',{templateUrl:"test.html", controller:function($scope,a,b) { $scope.name = "你好"+a; $scope.list = b.data; }, resolve:{ a:"myService", b:function($http,$timeout) { var promise = $timeout(function() { return $http.get("http://localhost:3000/person"); },3000); return promise; } }}); }]); </script> </body>
如果直接在控制器而不是resolve中請求,則index.html代碼如下。
<body ng-app="myApp"> <div ng-app="myApp"> <a ng-href="#/test">測試</a> <div ng-view></div> </div> <script> var app = angular.module("myApp",['ngRoute']); app.value("myService","張三"); app.config(['$routeProvider',function($routeProvide) { $routeProvide .when('/test',{templateUrl:"test.html", controller:function($scope,$http,$timeout,a) { $scope.name = "你好"+a; var promise = $timeout(function() { return $http.get("http://localhost:3000/person"); },3000); promise.then(function(response) { $scope.list = response.data; }); }, resolve:{ a:"myService" }}); }]); </script> </body>
兩者效果如下,可以看到寫在控制器中的代碼不僅需要自己處理邏輯(控制器不推薦寫太復雜的邏輯)從promise的success function中取得repsonse參數,而且頁面加載不一致,服務器獲取的數據在獲得后才加載,而在resolve中寫,只有等promise執行完畢后才會跳轉,然后同步加載整個頁面。
- redirectTo
值是一個字符串或一個函數,該屬性寫在otherwise中,代表着在when中找不到相應路徑時的重定向。如果是字符串,路徑會被替換成該值,如果是函數,它有三個參數,第一個是當前路徑的路由參數,第二個是當前路徑,第三個當前Url的查詢串,路徑會被替換成該函數的返回值,替換后都會觸發路由變化。
- reloadOnSearch
值是一個布爾值,為true的時候$location.search()發生變化時就會重新加載路由,location.search是從當前URL的?號開始(包括?號)的字符串。
④ $routeParams
我們可以在路由參數的前面加上:號,AngularJS會把它解析出來並傳遞給$routeParams。
下面的例子中我們將123456傳給value,AngularJS把其解析出來,在$routeParams中添加一個名為value的鍵,值為123456,我們可以將該服務注入到控制器中使用。
test.html代碼如下。
<p>我是測試界面 {{ display }}</p>
<body ng-app="myApp"> <div ng-app="myApp"> <a ng-href="#/test/123456">測試</a> <div ng-view></div> </div> <script> var app = angular.module("myApp",['ngRoute']); app.config(['$routeProvider',function($routeProvide) { $routeProvide .when('/test/:value',{templateUrl:"test.html", controller:function($scope,$routeParams) { $scope.display = $routeParams.value; }}); }]); </script> </body>
⑤ 路由事件
$route服務在路由過程中的每個階段都會觸發不同的事件,可以為這些事件設置監聽器並做出響應。路由事件都是系統自動從$rootScope廣播下去的,我們最好的做法是在$rootScope中監聽,而最佳設置的地方就是run方法,可以保證不會漏掉任何路由變化。
下面是四種不同的路由事件。
- $routeChangeStart
AngularJS在路由改變之前就會廣播此事件,在廣播后,路由會開始加載路由變化所需要的所有依賴,並且模板和resolve鍵中的promise都會被resolve。 - $routeChangeSuccess
在路由的依賴加載,且resolve鍵中所有promise都resolve了就會廣播此事件。 - $routeChangeError
在resolve鍵中任何一個promise被拒絕或者失敗后會廣播此事件,也就是說,此事件與$routeChangeSuccess互斥。 -
$routeUpdate
在reloadOnSearch屬性設置為false的情況下,重新使用某個控制器的實例會廣播該事件。