1. 程式人生 > >ui-router - 路由控制$stateProvider

ui-router - 路由控制$stateProvider

在你的應用中大多數狀態都有與其相關聯的 url,路由控制不是設計完成 state 之後的事後想法,而是開始開發時就應該考慮的問題。

這裡是如何設定一個基本url。

1
2
3
4
5
$stateProvider
    .state('contacts', {
        url: "/contacts",
        templateUrl: 'contacts.html'
    })

當我們訪問index.html/contacts

時, 'contacts'狀態將被啟用,同時index.html中的ui-view將被'contacts.html'填充。或者,通過transitionTo('contacts')方法將狀態轉變到'contacts'狀態,同時 url 將更新為index.html/contacts

URL引數

基本引數

通常,url動態部分被稱為引數,有幾個選項用於指定引數。基本引數如下:

1
2
3
4
5
6
7
8
9
10
$stateProvider
    .state('contacts.detail', {
        // 這裡設定了url引數
        url: "/contacts/:contactId",
        templateUrl: 'contacts.detail.html',
        controller: function ($stateParams) {
            // If we got here from a url of /contacts/42
            expect($stateParams).toBe({contactId: 42});
        }
    })

或者,你也可以使用花括號的方式來指定引數:

1
2
// 與前面的設定方法等效
url: "/contacts/{contactId}"

示例:

  • '/hello/' - 只匹配'/hello/'路徑,沒有對斜槓進行特殊處理,這種模式將匹配整個路徑,而不僅僅是一個字首。
  • '/user/:id' - 匹配'/user/bob''/user/1234!!!',甚至還匹配 '/user/'
    ,但是不匹配'/user''/user/bob/details'。第二個路徑段將被捕獲作為引數"id"
  • '/user/{id}' - 與前面的示例相同,但使用花括號語法。

含正則表示式的引數

使用花括號的方式可以設定一個正則表示式規則的引數:

1
2
// 只會匹配 contactId 為1到8位的數字
url: "/contacts/{contactId:[0-9]{1,8}}"

示例:

  • '/user/{id:[^/]*}' - 與'/user/{id}'相同
  • '/user/{id:[0-9a-fA-F]{1,8}}' - 與前面的示例相似,但只匹配1到8為的數字和字元
  • '/files/{path:.*}' - 匹配任何以'/files/'開始的URL路徑,並且捕獲剩餘路徑到引數'path'中。
  • '/files/*path' - 與前面相同,捕獲所有特殊的語法。

警告:不要把捕獲圓括號寫進正則表示式,ui-router 的 UrlMatcher 將為整個正則表示式新增捕獲。

Query Parameters

可以通過?來指定引數作為查詢引數

1
2
url: "/contacts?myParam"
// 匹配 "/contacts?myParam=value"

如果你需要不止一個查詢引數,請用&分隔:

1
2
url: "/contacts?myParam1&myParam2"
// 匹配 "/contacts?myParam1=value1&myParam2=wowcool"

巢狀狀態的路由控制

附加的方式(預設)

在巢狀狀態的路由控制中,預設方式是子狀態的 url 附加到父狀態的 url 之後。

1
2
3
4
5
6
7
8
9
$stateProvider
  .state('contacts', {
     url: '/contacts',
     ...
  })
  .state('contacts.list', {
     url: '/list',
     ...
  });

路由將成為:

  • 'contacts'狀態將匹配"/contacts"
  • 'contacts.list'狀態將匹配"/contacts/list"。子狀態的url是附在父狀態的url之後的。

絕對路由(^)

如果你使用絕對 url 匹配的方式,那麼你需要給你的url字串加上特殊符號"^"

1
2
3
4
5
6
7
8
9
$stateProvider
  .state('contacts', {
     url: '/contacts',
     ...
  })
  .state('contacts.list', {
     url: '^/list',
     ...
  });

路由將成為:

  • 'contacts'狀態將匹配"/contacts"
  • 'contacts.list'狀態將匹配"/list"。子狀態的url沒有附在父狀態的url之後的,因為使用了^

$stateParams 服務

之前看到的$stateParams服務是一個物件,包含 url 中每個引數的鍵/值。$stateParams可以為控制器或者服務提供 url 的各個部分。
注意:$stateParams服務必須與一個控制器相關,並且$stateParams中的“鍵/值”也必須事先在那個控制器的url屬性中有定義。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 如果狀態中 url 屬性是:
url: '/users/:id/details/{type}/{repeat:[0-9]+}?from&to'

// 當瀏覽
'/users/123/details//0'

// $stateParams 物件將是
{ id:'123', type:'', repeat:'0' }

// 當瀏覽
'/users/123/details/default/0?from=there&to=here'

// $stateParams 物件將是
{ id:'123', type:'default', repeat:'0', from:'there', to:'here' }

使用$stateParams的兩個陷阱

  • 只有當狀態被啟用並且狀態的所有依賴項都被注入時,$stateParams物件才存在。這代表你不能再狀態的resolve函式中使用$stateParams物件,可以使用$state.current.params來代替。
1
2
3
4
5
6
7
8
9
10
$stateProvider.state('contacts.detail', {  
   resolve: { 
      someResolve: function($state){ 
         //*** 不能在這裡使用 $stateParams , the service is not ready ***//
         //*** 使用 $state.current.params 來代替 ***//
         return $state.current.params.contactId + "!" 
      }; 
   },
   // ...
})
  • 在狀態控制器中,$stateParams物件只包含那些在狀態中定義的引數,因此你不能訪問在其他狀態或者祖先狀態中定義的引數。
1
2
3
4
5
6
7
8
9
10
11
12
$stateProvider.state('contacts.detail', {
   url: '/contacts/:contactId',   
   controller: function($stateParams){
      $stateParams.contactId  //*** Exists! ***//
   }
}).state('contacts.detail.subitem', {
   url: '/item/:itemId', 
   controller: function($stateParams){
      $stateParams.contactId //*** 注意! DOESN'T EXIST!! ***//
      $stateParams.itemId //*** Exists! ***//  
   }
})

$urlRouterProvider

$urlRouterProvider負責處理在狀態配置中指定的url路由方式之外的 url 請求的路由方式。$urlRouterProvider負責監視$location,當$location改變後,$urlRouterProvider將從一個列表,一個接一個查詢匹配項,直到找到。所有 url 都編譯成一個UrlMatcher物件。

$urlRouterProvider有一些實用的方法,可以在module.config中直接使用。

when() for redirection 重定向

引數:

  • what String | RegExp | UrlMatcher,你想重定向的傳入路徑
  • handler String | Function 將要重定向到的路徑

handler 作為 String
如果handler是字串,它被視為一個重定向,並且根據匹配語法決定重定向的地址。

1
2
3
4
5
6
7
app.config(function($urlRouterProvider){
    // when there is an empty route, redirect to /index   
    $urlRouterProvider.when('', '/index');

    // You can also use regex for the match parameter
    $urlRouterProvider.when('/aspx/i', '/index');
})

handler 作為 Function
如果handler是一個函式,這個函式是注入一些服務的。如果$location匹配成功,函式將被呼叫。你可以選擇性注入$match

函式可以返回:

  • falsy 表明規則不匹配,$urlRouter將試圖尋找另一個匹配
  • String 該字串作為重定向地址並且作為引數傳遞給$location.url()
  • nothing或者任何為真的值,告訴$urlRouterurl 已經被處理

示例:

1
2
3
4
5
$urlRouterProvider.when(state.url, ['$match', '$stateParams', function ($match, $stateParams) {
    if ($state.$current.navigable != state || !equalForKeys($match, $stateParams)) {
        $state.transitionTo(state, $match, false);
    }
}]);

otherwise() 無效路由

引數:

  • path String | Function 你想重定向url路徑或者一個函式返回url路徑。函式可以包含$injector$location兩個引數。
1
2
3
4
5
6
7
8
9
10
app.config(function($urlRouterProvider){
    // 在配置(狀態配置和when()方法)中沒有找到url的任何匹配
    // otherwise will take care of routing the user to the specified url
    $urlRouterProvider.otherwise('/index');

    // Example of using function rule as param
    $urlRouterProvider.otherwise(function($injector, $location){
        ... some advanced code...
    });
})

rule() 自定義url處理

引數:

  • handler Function 一個函式,包含$injector$location兩個服務作為引數,函式負責返回一個有效的路徑的字串。
1
2
3
4
5
6
7
app.config(function($urlRouterProvider){
    // Here's an example of how you might allow case insensitive urls
    $urlRouterProvider.rule(function ($injector, $location) {
        var path = $location.path(), normalized = path.toLowerCase();
        if (path != normalized) return normalized;
    });
})

$urlMatcherFactory 和 UrlMatchers

定義了url模式和引數佔位符的語法。$urlMatcherFactory是在幕後被$urlRouterProvider呼叫,來快取編譯後的UrlMatcher物件,而不必在每次 location 改變後重新解析url。大多數使用者不需要直接使用$urlMatcherFactory方法,但是在狀態配置中非常實用,可以使用$urlMatcherFactory方法來生成一個UrlMatcher物件,並在狀態配置中使用該物件。

1
2
3
4
var urlMatcher = $urlMatcherFactory.compile("/home/:id?param1");
$stateProvider.state('myState', {
    url: urlMatcher 
});