深刻理解ANGULARUI路由_UI-ROUTER

最近在用 ionic寫個webapp 看到幾個demo中路由有好幾種,搞的有點暈,查下資料研究下,作個筆記,其中大部分爲摘抄別人的,作個說明省得被人吐槽。javascript

Angularjs ui-router - 組件:html

  • $state / $stateProvider:管理狀態定義、當前狀態和狀態轉換。包含觸發狀態轉換的事件和回調函數,異步解決目標狀態的任何依賴項,更新$location到當前狀態。因爲狀態包含關聯的 url,經過$urlRouterProvider生成一個路由規則來執行轉換的狀態。前端

  • ui-view指示器:渲染狀態中定義的視圖,是狀態中定義的視圖的一個佔位符。java

  • $urlRouter / $urlRouterProvider:管理了一套路由規則列表來處理當$location發生變化時如何跳轉。最低級的方式是,規則能夠是任意函數,來檢查$location,並在處理完成時候返回true。支持正則表達式規則和經過$urlMatcherFactory編譯的UrlMatcher對象的 url 佔位符規則。web

  • $urlMatcherFactory:將 url和佔位符編譯爲UrlMatcher對象。除了$routeProvider支持的佔位符語法以外,它還支持擴展語法,容許一個正則表達式指定佔位符,而且可以提取命名參數和查詢url的一部分。正則表達式

  • $templateFactory - 經過$http / $templateCache來加載模板,供狀態配置中使用。編程

 

AngularJS不須要任何第三方庫,利用自身集成的各個模塊即可開發出功能齊全的web應用,不過活躍的AngularJS社區也開發了不少可以最大限度強化web應用的編程庫。本文帶讀者瞭解專業開發使用的模塊AngularUI中的ui-路由(ui-router)。AngularUI庫已經被分紅了幾個模塊,用戶能夠只選擇載入本身感興趣的模塊,而不用載入整個庫。api

UI-Router

UI-Router被認爲是AngularUI爲開發者提供的最實用的一個模塊,它是一個讓開發者可以根據URL狀態或者說是'機器狀態'來組織和控制界面UI的渲染,而不是僅僅只改變路由(傳統AngularJS應用實用的方式)。該模塊爲開發者提供了不少最視圖(view)額外的控制。開發者能夠建立嵌套分層的視圖、在同一個頁面使用多個視圖、讓多個視圖控制某個視圖等更多的功能。即便是很是複雜的web應用,UI-Router也能夠極佳地駕馭。數組

安裝

安裝方式能夠選擇下載發行版本或者使用Bower(前端包管理器):promise

$ bower install angular-ui-router --save

同時也須要將源文件包含到頁面中:

<script type="text/javascript" src="app/bower_components/angular-ui-router/release/angular-ui-router.js"></script>

接下來,將UI-Router做爲web應用的依賴,注入到主程序:

angular.module('myApp', ['ui.router']);

與集成的ngRoute服務不一樣的是,UI-Router能夠將視圖嵌套,由於它基於的是操做狀態而僅非URL。與傳統作法使用ng-view不一樣的是,在ngRoute裏須要使用ui-view服務。當在ui-router中處理路由和狀態時,開發者的重心是當前的狀態是什麼以及在哪個頁面裏。

<div ng-controller="DemoController"> <div ui-view></div> </div>

和ngRoute同樣,爲特定狀態指定的模板將會放在<div ui-view></div>元素中。在這些模板中也能夠包含本身的ui-view,這就是在同一個路由下實現嵌套視圖的方法。要定義一個路由,與傳統的方法相同:使用.config方式,但使用的不是$routeProvider而是$stateProvider

.config(function($stateProvider, $urlRouterProvider) { $stateProvider .state('start', { url: '/start', templateUrl: 'partials/start.html' }) });

上述代碼在設置對象上定義了一個叫start的狀態。設置對象stateConfig和路由設置對象的選項是很是類似的。

模板,模板路徑,模板Provider

開發者能夠在每一個視圖下使用以下方式來設置模板 - template - HTML字符串,或者是返回HTML字符串的函數 - templateUrl - HTML模板的路徑,或者是返回HTML模板路徑的函數 - templateProvider - 返回HTML字符串的函數 例如:

$stateProvider.state('home', { template: '<h1>Hello {{ name }}</h1>' });

控制器

ngRoute類似,開發者能夠指定任何已經被註冊的控制器,或者在路由裏面建立一個做爲控制器的函數。但若是沒有定義模板,控制器將無效。

預載入Resolve

使用預載入功能,開發者能夠預先載入一系列依賴或者數據,而後注入到控制器中。在ngRouteresolve選項能夠容許開發者在路由到達前載入數據保證(promises)。在使用這個選項時比使用angular-route有更大的自由度。

預載入選項須要一個對象,這個對象的key即要注入到控制器的依賴,這個對象的value爲須要被載入的factory服務。

若是傳入的時字符串,angular-route會試圖匹配已經註冊的服務。若是傳入的是函數,該函數將會被注入,而且該函數返回的值即是控制器的依賴之一。若是該函數返回一個數據保證(promise),這個數據保證將在控制器被實例化前被預先載入而且數據會被注入到控制器中。

$stateProvider.state('home', { resolve: {  //這個函數的值會被直接返回,由於它不是數據保證 person: function() { return { name: "Ari", email: "ari@fullstack.io" } },  //這個函數爲數據保證, 所以它將在控制器被實例化以前載入。 currentDetails: function($http) { return $http({ method: 'JSONP', url: '/current_details' }); },  //前一個數據保證也可做爲依賴注入到其餘數據保證中!(這個很是實用) facebookId: function($http, currentDetails) { $http({ method: 'GET', url: 'http://facebook.com/api/current_user', params: { email: currentDetails.data.emails[0] } }) } },  //定義控制器 controller: function($scope, person, currentDetails, facebookId) { $scope.person = person; } })

URL

url選項將會爲該應用的狀態指定一個URL基於用戶瀏覽該應用所在的狀態。這樣當在瀏覽該應用的時候便能實現深度連接的效果。 該選項與ngRoute的URL類似,但能夠被視爲對ngRoute主要的升級,在接下來的文章裏你便會承認這一點。開發者能夠這樣指定一個基本的路由。

$stateProvider
      .state('inbox', { url: '/inbox', template: '<h1>Welcome to your inbox</h1>' });

當用戶瀏覽到/inbox時,該應用將狀態改成inbox同時向主ui-view元素中插入模板中的內容('Welcome to your inbox')。URL參數有多個選項,所以它很是強大。開發者能夠像設置ngRoute同樣設置最基本的參數:

$stateProvider
      .state('inbox', { url: '/inbox/:inboxId', template: '<h1>Welcome to your inbox</h1>', controller: function($scope, $stateParams) { $scope.inboxId = $stateParams.inboxId; } });

如今將:inboxId最爲URL的第二個部分,例如:訪問/inbox/1,那麼$stateParams.inboxId就爲1($stateParams爲{inboxId:1})。同時也可以使用不一樣的語法:

url: '/inbox/{inboxId}'

路徑必須匹配URL,與ngRoute不一樣的是,當用戶訪問到/inbox/時,上面的的路徑會被激活,然而當訪問到/inbox時不會被激活。路徑同時也使開發者可使用正則表達式來匹配,例如:

 // 限定id爲6位16進制數字 url: '/inbox/{inboxId:[0-9a-fA-F]{6}}',  // 或者  // 匹配任何在 `/inbox`後面的url(慎用)並匹配值到indexId url: '/inbox/{inboxId:.*}'

注意,在路由中目前還沒法使用路由組,路由數據預載入器沒法預載入。

在路徑裏也能夠指定查詢參數:

 // /inbox?sort=ascending 將會被匹配 url: '/inbox?sort'

嵌套路由

使用url參數能夠實現嵌套的路由,有了嵌套路由即可在同一個模板同一個路由實現多層次的ui-view,例如在/inbox中嵌入更多路由:

$stateProvider
      .state('inbox', { url: '/inbox/:inboxId', template: '<div><h1>Welcome to your inbox</h1>\ <a ui-sref="inbox.priority">Show priority</a>\ <div ui-view></div>\ </div>', controller: function($scope, $stateParams) { $scope.inboxId = $stateParams.inboxId; } }) .state('inbox.priority', { url: '/priority', template: '<h2>Your priority inbox</h2>' });

第一個路由是傳統的,注意第二個,它是/inbox下的一個子路由:state( . )語法指定了它使子路由。/inbox/1將匹配第一個路由,而/index/1/priority會匹配第二個路由。使用這種語法,在父視圖中的ui-view元素將會由第二個路由控制。

Params 路由參數

params選項是一個包含路徑中的參數和正則表達式匹配結果的數組。該選項不能和url選項混用!當某狀態被激活時,應用將這個數組賦值給$stateParams服務。

Views 視圖

開發者能夠在一個狀態中設置多個有名稱的視圖。該功能在ui-router中很強大,開發者能夠在同一個模板中改變和切換不一樣的視圖。

<若是設置了視圖選項,則該狀態的‘template’,‘templateUrl’及‘templateProvider’將被忽略。若是想在路由裏包含父級模板,就須要建立一個包含模板的抽象模板。

例若有這樣的視圖:

<div> <div ui-view="filters"></div> <div ui-view="mailbox"></div> <div ui-view="priority"></div> </div>

接下來就能夠建立將被分別被插入到上述ui-view的有命名的視圖了,每一個子視圖能夠包含本身的模板、控制器和預載入數據。

$stateProvider
  .state('inbox', { views: { 'filters': { template: '<h4>Filter inbox</h4>', controller: function($scope) {} }, 'mailbox': { templateUrl: 'partials/mailbox.html' }, 'priority': { template: '<h4>Priority inbox</h4>', resolve: { facebook: function() { return FB.messages(); } } } } });

abstract 抽象模板

抽象模板不能被激活,可是它的子模板能夠被激活。抽象模板能夠提供一個包括了多個有名的視圖的模板,或者它能夠傳遞做用域變量$scope給子模板。使用它能夠在同一個url下傳遞自定義數據或者預載入的依賴。除了須要添加abstract屬性外,其餘設置和設定一個常規狀態是相同的:

$stateProvider
  .state('admin', { abstract: true, url: '/admin', template: '<div ui-view></div>' }) .state('admin.index', { url: '/index', template: '<h3>Admin index</h3>' }) .state('admin.users', { url: '/users', template: '<ul>...</ul>' });

onEnter,onExit 回調函數

當應用進入或者離開當前狀態的視圖時會調用這兩個函數。這兩個函數能夠訪問預載入的數據。這兩個回調函數使開發者能夠根據狀態改變來採起某些動做,例如在用戶要離開時能夠彈出對話框‘你肯定嗎?’以及防止意外操做等。

Data 數據

自定義數據也能夠被附加到狀態控制對象state configObject.該數據和預載入數據resolve屬性類似,可是該數據不會被注入到控制器中,promise也不會被預載入,它的用途是從父狀態傳遞數據到子狀態。

事件

和ngRoute相同的是,angular-route服務會在不一樣的狀態生命週期lifecycle裏啓動某些事件events。監聽$scope對象即可以捕獲這些事件而後採起不一樣的響應或者操做。以下的事件將會在$rootScope上觸發,所以在任何$scope對象上均可以監聽到這些事件。

狀態改變事件

$scope.$on('$stateChangeStart', function(evt, toState, toParams, fromState, fromParams), {  // 若是須要阻止事件的完成 evt.preventDefault(); });

能夠觸發的事件包括:

stateChangeStart

當狀態改變開始的時候被觸發

$stateChangeSuccess

當狀態改變成功後被觸發

$stateChangeError

當狀態改變遇到錯誤時被觸發,錯誤一般是目標沒法載入,須要預載入的數據沒法被載入等。

視圖載入事件

視圖載入階段ui-router也提供了一些事件

$viewContentLoading

當視圖正在被載入且在DOM被渲染以前觸發。

$scope.$on('$viewContentLoading', function(event, viewConfig){  // 獲取任何視圖設置的參數,以及一個特殊的屬性:viewConfig.targetView });

$viewContentLoaded

當視圖被載入且DOM已經渲染完成後被觸發。

$stateParams 狀態參數

在上面說起使用$stateparams來提取在url中的不一樣參數。該服務的做用是處理url的不一樣部分。例如,當上述的inbox狀態是這樣時:

url: '/inbox/:inboxId/messages/{sorted}?from&to'  //當用戶訪問者連接時: '/inbox/123/messages/ascending?from=10&to=20'

$stateParams對象的值爲:

{inboxId: '123', sorted: 'ascending', from: 10, to: 20}

$urlRouterProvider

和ngRoute同樣,開發者能夠在該對象上設定特定的URL被激活時作什麼的規則。因爲設定好的狀態在特定的url被訪問是會自動激活,因此$urlRouterProvider沒有必要用來管理激活和載入狀態。但當須要管理哪些被髮生在當前狀態以外的做用域scope時它會很是有用,例如在重定向或者安全驗證的時候。在模塊的設置函數裏即可使用$urlRouterProvider。

when()

該函數須要兩個參數:1.當前的路徑,2.須要重定向到的路徑(或者是須要在路徑被訪問是運行的函數)。設置重定向前須要爲$urlRouterProvider設置when函數來接受一個字符串。例如,當但願重定向一個空的路由到/inbox:

.config(function($urlRouterProvider) { $urlRouterProvider.when('', '/inbox'); });

若是傳遞的是函數,在路徑被匹配時該函數會被執行,處理器返回以下3個值中的一個: - falsy,該回應告訴$urlRouter沒有匹配到當前url規則,應該嘗試匹配新的路徑,這樣能保證用戶訪問了正常的路徑。 - 字符串,$urlRouter將該字符串當作重定向的路徑。 - TRUE 或者 undefined,該回應告訴$urlRouter,url已被處理

otherwise()

和ngRoute的otherwise()函數類似,在用戶提交的路徑沒有被定義的時候它將重定向到指定的頁面。這是個建立’默認‘路徑的好方法。 otherwise()只接受一個參數,要麼函數要麼字符串,字符串必須爲合法的url路由地址,函數則會在沒有任何路徑被匹配的時候被運行。

.config(function($urlRouterProvider) { $urlRouterProvider.otherwise('/');  // or $urlRouterProvider.otherwise( function($injector, $location) { $location.path('/'); }); });

rule()

若是想越過任何URL的匹配或者在其餘路由前作路由修改,則可使用rule()函數。在使用它的時候必須返回一個合法的表明路徑的字符串。

app.config(function($urlRouterProvider){ $urlRouterProvider.rule( function($injector, $location) { return '/index'; }); })

總結

本文涵蓋了ui-router深度及幾乎所有的功能。但願你也發現這個庫的強大和實用,並在下一個項目中實用這些強大的功能。

相關文章
相關標籤/搜索