Angular學習筆記(17)—ui-router

安裝

$ bower install angular-ui-router --save

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

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

現(xiàn)在,不同于內(nèi)置的ngRoute服務,由于ui-router基于狀態(tài)工作他宛,而不是簡單的url,因此可以將它嵌套在視圖中欠气。
在處理ngRoute服務時我們不再使用ng-view厅各,而改為使用ui-view指令。
ui-router內(nèi)處理路由和狀態(tài)時预柒,我們主要關心的是應用程序處在哪個狀態(tài)以及Web應用當前處在哪個路由位置队塘。

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

定義在任意給定狀態(tài)內(nèi)的模板都處在<div ui-view></div>元素內(nèi)。此外卫旱,每個模板都可以包含自己的ui-view人灼。 這事實上就允許你在路由中嵌套視圖。定義路由:

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

這一步給狀態(tài)配置對象分配了一個名為start的狀態(tài)顾翼。這個狀態(tài)配置對象的參數(shù)如下:

1.template投放、templateUrl、templateProvider

在每個視圖上設置模板的方式有三種适贸。

  • template:一個HTML內(nèi)容字符串或者返回HTML的函數(shù)
  • templateUrl:一個模板URL路徑字符串或者是返回URL路徑字符串的函數(shù)
  • templateProvider:一個返回HTML內(nèi)容字符串的函數(shù)

2.controller

可以給已經(jīng)注冊好的控制器關聯(lián)一個URL(使用字符串)灸芳,也可以創(chuàng)建一個控制器函數(shù)作為狀態(tài)控制器。如果沒有定義模板拜姿,就不會創(chuàng)建這個控制器烙样。

3.resolve

我們還可以使用resolve功能解析要注入到控制器中的依賴列表。這個resolve選項就是一個對象蕊肥,其中鍵就是要注入到控制器中的依賴名稱谒获,而其值就是待解析的factories
如果傳入一個字符串壁却,angular-route會嘗試匹配一個現(xiàn)有的已注冊的服務批狱。如果傳入一個函數(shù),則注入這個函數(shù)展东,而函數(shù)的返回值就是依賴赔硫。如果這個函數(shù)返回一個promise,它會在控制器被實例化之前解析盐肃,同時其值(就像ngRoute)會注入到控制器中爪膊。

$stateProvider.state('home', {
    resolve: {
        // 當結果不是promise時立即返回
        person: function() {
            return {
                name: "Ari",
                email: "ari@fullstack.io"
            }
        },
        // 這個函數(shù)返回一個promise权悟,它會在控制器實例化之前解析
        currentDetails: function($http) {
            return $http({
                method: 'JSONP',
                url: '/current_details'
            });
        },
        // 還可以在另一個解析中使用上面返回的promise
        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;
    }
});

4.url

url選項可以給應用程序的狀態(tài)分配一個唯一的URL。這個url選項提供了與深度鏈接同樣的功能推盛,它通過狀態(tài)導航應用峦阁,而不是簡單地通過URL導航。
基本路由可以像這樣指定:

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

當用戶導航到/inbox時小槐,應用會轉換到inbox狀態(tài)拇派,然后使用模板內(nèi)容填充主要的ui-view指令。
URL可以接受一系列不同的選項凿跳,它還可以在url中設置基本的參數(shù)件豌。

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

應用會捕獲作為URL第二個組成部分的:inboxId。例如控嗜,如果用戶轉換到/inbox/1茧彤,$stateParams.inboxId就會變成1(因為$stateParams{inboxId: 1})。
還可以使用不同的語法:

url: '/inbox/{inboxId}'

這里路徑必須與URL精確匹配疆栏。和ngRoute不同曾掂,如果用戶導航到/inbox/,上面的路徑能夠正常工作壁顶。但是珠洗,當導航導到/inbox時,上述示例配置中的狀態(tài)不會被激活若专。
此外许蓖,你還可以在路徑參數(shù)內(nèi)使用正則表達式,因此你可以設置一個匹配路由的規(guī)則调衰。

// 只匹配包含6個十六進制數(shù)字的inbox ID
url: '/inbox/{inboxId: [0-9a-fA-f]{6}}',
// 或者匹配每個URL中`/inbox`后面的`inboxId`(全部捕獲)
url: '/inbox/{inboxId:.*} '

注意膊爪,不能在路由內(nèi)使用正則捕獲組,因為路由解析器將無法解析這個路由嚎莉。
甚至還可以在路由中指定查詢參數(shù):

// 匹配諸如/inbox?sort=ascending形式的路由
url: '/inbox?sort'

5.嵌套路由

你可以使用url參數(shù)以插入路由的方式提供嵌套路由米酬。這讓你可以在頁面或者模板內(nèi)有多個ui-views

$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>'
});

第一個路由會按預期匹配∏髀幔現(xiàn)在這里有了第二個路由赃额,也就是一個匹配父路由inbox之下的子路由。

  • /inbox/1匹配第一個狀態(tài)叫确。
  • /inbox/1/priority匹配第二個狀態(tài)跳芳。

使用這種語法,你可以在父路由內(nèi)嵌套URL启妹。父視圖中的ui-view會解析priority收件箱。

6.params

params選項是一個參數(shù)名數(shù)組或者是一個正則表達式數(shù)組醉旦。不能將這個選項與url選項聯(lián)合使用饶米。當狀態(tài)被激活時桨啃,這些參數(shù)會被填充到$stateParams服務中。

7.views

ui-router的一個強大的特性就是可以在一個狀態(tài)內(nèi)設置多個命名視圖檬输。在獨立的視圖內(nèi)照瘾,你可以在獨立模板中定義多個要引用的視圖。
如果設置了views參數(shù)丧慈,那么狀態(tài)的templateUrl析命、templatetemplateProvider就會被忽略。如果你想在路由中包含父模板逃默,就需要創(chuàng)建一個包含模板的抽象狀態(tài)鹃愤。
比方說我們有一個視圖看起來像這樣:

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

現(xiàn)在,你可以創(chuàng)建命名視圖來填充每個獨立的模板完域。每個子視圖都可以包含它自己的模板软吐、控制器和使用resolve關鍵字解析的數(shù)據(jù)。

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

8.abstract

抽象模板永遠不能直接激活吟税,但是可以設置被激活的子節(jié)點凹耙。
你可以使用抽象模板提供一個模板包裝器來包裹多個命名視圖,或者傳遞$scope對象給子節(jié)點肠仪。你還可以使用它們來傳遞解析后的依賴或者自定義數(shù)據(jù)肖抱,或者在同一url下嵌套多個路由(比如,所有的路由都在/adminURL之下)异旧。
設置抽象模板與設置常規(guī)狀態(tài)一樣意述,區(qū)別只在于設置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>'
  });

9.onEnter、onExit

Angular會在用戶(分別)進入或者離開視圖時調用這些回調函數(shù)泽艘。對于這兩個選項欲险,你可以設置希望調用的函數(shù)。這些函數(shù)可以訪問被解析的數(shù)據(jù)匹涮。
這些回調函數(shù)讓你可以在新視圖上或者進入另一個狀態(tài)時觸發(fā)某個行為天试。使用它們可以很好地實現(xiàn)一個“你確定嗎?”形式的模態(tài)視圖然低,或者在用戶進入這個狀態(tài)之前要求用戶登錄喜每。

10.data

你可以附加任意數(shù)據(jù)給你的狀態(tài)配置對象configObject。這個選項跟resolve屬性很像雳攘,但是它的數(shù)據(jù)不會被注入到控制器中带兜,promise也不會被解析。
當需要從父狀態(tài)給子狀態(tài)傳遞數(shù)據(jù)時吨灭,這個選項特別有用刚照。

事件

angular-route服務會在狀態(tài)生命周期的不同階段觸發(fā)不同的事件。
在應用程序內(nèi)可以通過監(jiān)聽$scope對象的方式附加函數(shù)給這些事件喧兄。以下所有事件都會觸發(fā)在$ootScope上无畔,因此可以在任意$scope對象上監(jiān)聽這些事件啊楚。

1.狀態(tài)改變事件

可以使用如下方式監(jiān)聽這個事件:

$scope.$on('$stateChangeStart',
  function(evt, toState, roParams, fromState, fromParams) { 
      // 可以阻止這一狀態(tài)完成
      evt.preventDefault();
  });

這個事件可能會以如下方式觸發(fā)。
$stateChangeStart從一個狀態(tài)開始過渡到另一個狀態(tài)時觸發(fā)這個事件浑彰。 $stateChangeSuccess從一個狀態(tài)過渡到下一個狀態(tài)完成時觸發(fā)這個事件恭理。 $stateChangeError當過渡期間發(fā)生錯誤時觸發(fā)這個事件。通常郭变,模板不能被解析或者解析promise失敗時會引發(fā)錯誤颜价。

2.視圖加載事件

ui-router還在視圖加載階段提供了事件。
$viewContentLoading視圖開始加載時诉濒,DOM被渲染之前周伦,觸發(fā)這個事件。
你可以像這樣監(jiān)聽這個事件:

$scope.$on('$viewContentLoading', 
  function(event, viewConfig) {
      // 在這里可以訪問所有視圖配置屬性 
      // 以及一個特殊的“targetView”屬性 
      // viewConfig.targetView
  });

$viewContentLoaded在視圖加載完成以及DOM渲染之后觸發(fā)這個事件循诉。

$stateParams

$stateParams服務展示了如何根據(jù)URL的不同組成部分處理數(shù)據(jù)横辆。
例如,如果在inbox狀態(tài)中有個看起來像這樣的URL:

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

你可以使用路由提供程序構建規(guī)則茄猫,規(guī)定當特定的URL被激活時會發(fā)生什么狈蚤。 創(chuàng)建的這些狀態(tài)負責在不同的URL中激活自身,因此不一定需要$urlRouterProvider來管理激活和加載狀態(tài)划纽。當你想要管理發(fā)生在狀態(tài)作用域之外的行為時脆侮,它就可以派上用場了,比如重定向或者身份驗證勇劣。
你可以在模塊配置函數(shù)中使用$urlRouterProvider靖避。

when()

when()接受兩個參數(shù):想要匹配的入口路徑和用于重定向的路徑(或者是在路徑匹配時調用的函數(shù))。
為了設置重定向比默,需要給when方法設置一個字符串參數(shù)幻捏。
例如,如果想將一個空路由重定向到/inbox:

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

如果傳入一個函數(shù)命咐,它會在路徑匹配時調用篡九。這個處理程序可能返回以下三個值中的一個。

  • falsy:這個值告訴$urlRouter該規(guī)則不匹配醋奠,同時它應該嘗試找到一個不同的狀態(tài)來匹配榛臼。如果想要確保用戶可以正確地訪問一個URL,它將很有幫助窜司。
  • 字符串:$urlRouter會把這個字符串值當作重定向的URL沛善。
  • truthy or undefined:這個值讓$urlRouter知道已經(jīng)處理了URL。

otherwise()

otherwise()方法在沒有其他路由匹配時發(fā)起重定向塞祈。這個方法是創(chuàng)建默認URL的一種很好的方式金刁。
otherwise()方法接受一個參數(shù):一個字符串或者函數(shù)。
如果傳入一個字符串,任何無效或者不匹配的路由都會重定向到字符串指定的URL尤蛮。
如果傳入一個函數(shù)漠秋,它會在沒有其他路由匹配時被調用,同時負責處理返回結果抵屿。

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

rule()

如果想要繞過所有的URL匹配,或者想要在操作其他路由之前對路由做一些操作捅位, 可以使用rule()函數(shù)轧葛。
使用rule()函數(shù)時必須返回一個有效路徑字符串。

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

創(chuàng)建一個導航程序

當我們想要為用戶創(chuàng)建一個注冊向導的時候艇搀,就需要使用ui-router了尿扯,這是一個非常合適的應用場景。
我們將使用ui-router創(chuàng)建一個快速注冊服務焰雕,它包含一個控制器衷笋,用于處理注冊任務。首先矩屁,需要創(chuàng)建應用視圖:

<div ng-controller="WizardSignupController"> 
    <h2>Signup wizard</h2>
    <div ui-view></div>
</div>

接下來辟宗,在這個注冊向導中還需要有三個階段。

  • start:在這個階段吝秕,我們獲取用戶名并向其介紹注冊向導泊脐。
  • email:在這里,接受用戶的郵件烁峭。
  • finish:此時容客,用戶完成注冊過程,我們要向其展示一個完整的頁面约郁。

在真實的應用中缩挑,finish階段應該將注冊資料發(fā)送給服務器,同時進行真實的注冊 操作鬓梅。在這里供置,由于沒有后端,因此暫時只顯示這個視圖己肮。
這個注冊程序依賴于wizardapp.controllers模塊士袄,我們將在其中編寫包含控制器:WizardSignupController

angular.module('wizardApp', [ 
    'ui.router', 
    'wizardapp.controllers'
]);

WizardSignupController簡單地提供了$scope.user對象谎僻,在注冊過程以及注冊行為中娄柳,我 們都會使用這個對象。

angular.module('wizardapp.controllers', []) 
  .controller('WizardSignupController', 
      function($scope, $state) { 
        $scope.user = {}; 
        $scope.signup = function() {}
  });

向導程序邏輯覆蓋了大部分工作艘绍。你可以將這些邏輯設置到應用的config()函數(shù)中:

angular.module('wizardApp', [
    'ui.router', 'wizardapp.controllers'
])
.config(function($stateProvider, $urlRouterProvider) { 
    $stateProvider
        .state('start', {
            url: '/step_1',
            /templateUrl: 'partials/wizard/step_1.html' 
        })
        .state('email', {
            url: '/step_2',
            templateUrl: 'partials/wizard/step_2.html'
        })
        .state('finish', {
            url: '/finish',
            templateUrl: 'partials/wizard/step_3.html' 
        });
});

設置這些選項之后赤拒,基本流程就全部完成了。現(xiàn)在,如果用戶導航到路由/step_1挎挖,他們將被定向到流程的起點这敬。盡管整個流程也可以都發(fā)生在根URL上(即/step_1),但你可能更希望將 它們放在子路由中(如/wizard/step_1)蕉朵。
為此崔涂,只需要設置一個包裝其他步驟的abstract狀態(tài)就可以了。

.config(function($stateProvider, $urlRouterProvider) { 
    $stateProvider
        .state('wizard', {
            abstract: true,
            url: '/wizard',
            template: '<div><div ui-view></div></div>' 
        })
        .state('wizard.start', {
            url: '/step_1',
            templateUrl: 'partials/wizard/step_1.html' 
        })
        .state('wizard.email', {
            url: '/step_2',
            templateUrl: 'partials/wizard/step_2.html' 
        })
        .state('wizard.finish', {
            url: '/finish',
            templateUrl: 'partials/wizard/step_3.html' 
        });
});

現(xiàn)在始衅,這些路由不再定義在頂級路由中了冷蚂,你可以將它們(子路由)安全地嵌套在/wizardURL內(nèi)。
此外汛闸,我們還想在注冊程序的尾部附加一個功能:在父控制器WizardSignupController上調用signup函數(shù)蝙茶。我們只需在向導程序的尾部設置一個控制器來調用$scope上的函數(shù)就行了。 由于整個向導程序都封裝在WizardSignupController中诸老,這就表示可以正常使用作用域嵌套作用域屬性隆夯。

.state('wizard.finish',{
    url: '/finish',
    templateUrl: 'partials/wizard/step_3.html', 
    controller: function($scope) { 
        $scope.signup();
    }
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市别伏,隨后出現(xiàn)的幾起案子蹄衷,更是在濱河造成了極大的恐慌,老刑警劉巖厘肮,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宦芦,死亡現(xiàn)場離奇詭異,居然都是意外死亡轴脐,警方通過查閱死者的電腦和手機调卑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來大咱,“玉大人恬涧,你說我怎么就攤上這事〔杲恚” “怎么了溯捆?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長厦瓢。 經(jīng)常有香客問我提揍,道長,這世上最難降的妖魔是什么煮仇? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任劳跃,我火速辦了婚禮,結果婚禮上浙垫,老公的妹妹穿的比我還像新娘刨仑。我一直安慰自己郑诺,他們只是感情好,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布杉武。 她就那樣靜靜地躺著辙诞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轻抱。 梳的紋絲不亂的頭發(fā)上飞涂,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機與錄音祈搜,去河邊找鬼封拧。 笑死,一個胖子當著我的面吹牛夭问,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播曹铃,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼缰趋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了陕见?” 一聲冷哼從身側響起秘血,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎评甜,沒想到半個月后灰粮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡饲嗽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年搁料,在試婚紗的時候發(fā)現(xiàn)自己被綠了盏浙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡柑肴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出旬薯,到底是詐尸還是另有隱情晰骑,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布绊序,位于F島的核電站硕舆,受9級特大地震影響,放射性物質發(fā)生泄漏骤公。R本人自食惡果不足惜抚官,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阶捆。 院中可真熱鬧耗式,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至娱挨,卻和暖如春余指,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背跷坝。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工酵镜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人柴钻。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓淮韭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贴届。 傳聞我的和親對象是個殘疾皇子靠粪,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容