URL Routing

URL Routing

参考原文:https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

Most states in your application will probably have a url associated with them. 

在你的应用程序中或多或少都会存在自定义状态(states),他们可能有一个与之关联的URL。

URL Routing was not an afterthought to the state mechanics, but was figured into the design from the beginning (all while keeping states separate from url routing)。

URL路由不是一个可有可无的状态机制,从一开始url路由被指向设计好的路径 (同时,来自URL路由的自定义状态保持独立)。

Here's how you set a basic url.

示例如下:

$stateProvider
    .state('contacts', {
        url: "/contacts",
        templateUrl: 'contacts.html'
    })

Now when the user accesses index.html/contacts then the 'contacts' state would become active and the main ui-view will be populated with the 'contacts.html' partial. 

当用户访问 index.html/contacts 的时候,'contacts' 状态会起作用,指定的视图将会被'contacts.html' 页面内容填充。

Alternatively, if the user were to transition to the 'contacts' state via transitionTo('contacts') then the url would be updated to index.html/contacts

简而言之,如果用户想要过渡到'contacts' 状态,URL就会更新到index.html/contacts。



URL Parameters

Basic Parameters

Often, URLs have dynamic parts to them which are called parameters.

通常,URLs的动态部分被称为状态变数(parameters)。

There are several options for specifying parameters. 

这有几个选项用于指定状态变数(parameters

 A basic parameter looks like this:

一个简单的状态变数(parameters如下:

$stateProvider
    .state('contacts.detail', {
        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"});
        }
    })

Alternatively you can also use curly brackets:

亦或用花括号:

// identical to previous example
url: "/contacts/{contactId}"

Examples:

示例:


  • '/hello/' - Matches only if the path is exactly '/hello/'. There is no special treatment for trailing slashes, and patterns have to match the entire path, not just a prefix.

'/hello/' - 只能匹配完全符合 '/hello/'的路径。这里的斜杠没有特殊处理,这种模式只能匹配整个路径,而不是仅仅作为前缀来匹配。

  • '/user/:id' - Matches '/user/bob' or '/user/1234!!!' or even '/user/' but not '/user' or '/user/bob/details'. The second path segment will be captured as the parameter 'id'.

'/user/:id' 可以匹配'/user/bob' 或 '/user/1234!!!' 甚至 '/user/'也能匹配。但不能匹配'/user' 或 '/user/bob/details'。第二个路径片段,作为参数id被捕捉。

  • '/user/{id}' - Same as the previous example, but using curly brace syntax.

'/user/{id}'用法同上例,只是用了花括号语法。

  • '/user/{id:int}' - The param is interpreted as Integer.

'/user/{id:int}' - 参数会被转化为整数。

Note:

注意:


  • Parameter names may contain only word characters (latin letters, digits, and underscore) and must be unique within the pattern (across both path and search parameters).

状态变parameters 的命名只能包含字符(拉丁字母,数字,下划线)并且在该模式内必须确保唯一(该模式中的路径和查询状态变parameters

Using Parameters in Links

To create a link that passes parameters, use the state name like a function and pass it an object with parameter names as keys. The proper href will be generated.

要创建传递状态变parameters的链接,状态名类似一个函数,传入以状态变parameters为属性的对象。这样就能生成你想要的链接。

For example, using the above state which specified a contactId parameter, create a link like so:

例如,使用上文中的指定状态变parameterscontactId 的状态,生成一个链接如下:

<a ui-sref="contacts.detail({contactId: id})">View Contact</a>


The value for id can be anything in scope.

在规定范围内id的值没有限制。(译者:文章中没看到规定范围的定义。猜测为latin letters, digits, and underscore

Regex Parameters

A bonus to using curly brackets is the ability to set a Regular Expression rule for the parameter:

使用花括号语法的一个好处是能够在状态变量parameters)中使用正则表达式:

// will only match a contactId of one to eight number characters
url: "/contacts/{contactId:[0-9]{1,8}}"

Examples:

  • '/user/{id:[^/]*}' - Same as '/user/{id}' from the previous example.

  • 在上一个例子中,'/user/{id:[^/]*}' - 等同于 '/user/{id}' 

  • '/user/{id:[0-9a-fA-F]{1,8}}' - Similar to the previous example, but only matches if the id parameter consists of 1 to 8 hex digits.

  • '/user/{id:[0-9a-fA-F]{1,8}}' -几乎与上例相同,除了只能匹配值为1-8的16进制。

  • '/files/{path:.*}' - Matches any URL starting with '/files/' and captures the rest of the path into the parameter 'path'.

  • '/files/{path:.*}' -匹配所有以'/files/'开头的路径并且在状态变量'path'中匹配剩余部分。

  • '/files/*path' - Ditto. Special syntax for catch all.

  • '/files/*path' - 同上。匹配所有的特殊语法。

Warning:

  • Don't put capturing parentheses into your regex patterns, the UrlMatcher in ui-router adds those itself around the entire regex. You're effectively introducing a second capture group for the same parameter, which trips up the numbering in the child URL. You can use non-capturing groups though, i.e. (?:...) is fine.

  • 不要把捕捉括号放到正则表达式中,因为ui-router中的链接匹配在整个正则表达式中自动添加捕捉括号。你有效的为同一个状态变量引入了第二个捕获组,这个捕获组挑出子URL的编号。当然你也可以用非捕获组,也就是 (?:...)。

  • Regular expression can't include forward slashes as that's route segment delimiter

  • 正则表达式不能用斜杠作为分隔符。

  • Route parameters with regular expressions can't be optional or greedy

  • 路由状态变量为正则表达式,正则表达式不能是可选的或贪婪匹配。

Query Parameters

You can also specify parameters as query parameters, following a '?':

你可以指定参数作为查询参数,尾部追加?即可

url: "/contacts?myParam"
// will match to url of "/contacts?myParam=value"

If you need to have more than one, separate them with an '&':

如果你需要一个以上的参数,用&分隔开:

url: "/contacts?myParam1&myParam2"
// will match to url of "/contacts?myParam1=value1&myParam2=wowcool"

Using Parameters without Specifying Them in State URLs

You still can specify what parameters to receive even though the parameters don't appear in the url. You need to add a new field params in the state and create links as specified in Using Parameters in Links

即使参数没有出现在URL中你依然可以指定接收参数。你需要在state方法中新加领域参数并在指定使用参数的链接中创建链接。

For example, you have the state.

.state('contacts', {
        url: "/contacts",
        params: {
            param1: null
        },
        templateUrl: 'contacts.html'
    })

The link you create is

<a ui-sref="contacts({param1: value1})">View Contacts</a>

Or can you pass them to $state.go() too.

$state.go('contacts', {param1: value1})

URL Routing for Nested States

多状态URL路由

Appended Routes (default)

附加路由(默认)

When using url routing together with nested states the default behavior is for child states to append their url to the urls of each of its parent states.

使用多状态URL路由默认会在状态的后面加入新的状态。

$stateProvider
  .state('contacts', {
     url: '/contacts',     ...
  })
  .state('contacts.list', {
     url: '/list',     ...
  });

So the routes would become:

这样一来路由变为如下:

  • 'contacts' state matches "/contacts"

  • 'contacts' 状态匹配 "/contacts"

  • 'contacts.list' state matches "/contacts/list". The urls were combined.

  • 'contacts.list' 状态匹配 "/contacts/list". The urls were combined.链接组合起来了。

Absolute Routes (^)

绝对路由(^)

If you want to have absolute url matching, then you need to prefix your url string with a special symbol '^'.

如果你需要使用绝对链接匹配,那么你需要加一个特殊前缀'^'。

$stateParams Service

As you saw previously the $stateParams service is an object that will have one key per url parameter. The $stateParams is a perfect way to provide your controllers or other services with the individual parts of the navigated url.

正如前文所见服务$stateParams是一个对象,它的每一个链接参数都会有一个值。$stateParams是分块控制链接的好方法。

Note: $stateParams service must be specified as a state controller, and it will be scoped so only the relevant parameters defined in that state are available on the service object.

注意: 服务$stateParams 指定为状态控制器,他会有指定的控制范围,所以只有定义在指定状中的态参数才能起作用。

// If you had a url on your state of:
url: '/users/:id/details/{type}/{repeat:[0-9]+}?from&to'

// Then you navigated your browser to:
'/users/123/details//0'

// Your $stateParams object would be
{ id:'123', type:'', repeat:'0' }

// Then you navigated your browser to:
'/users/123/details/default/0?from=there&to=here'

// Your $stateParams object would be
{ id:'123', type:'default', repeat:'0', from:'there', to:'here' }

Important $stateParams Gotcha

$stateParams需要明白的细节

In state controllers, the $stateParams object will only contain the params that were registered with that state. So you will not see params registered on other states, including ancestors.

状态控制器中 $stateParams 对象只包含注册其中的参数。其他状态中的参数不可见,即便是父状态中的参数也不可见。

$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 //*** Watch Out! DOESN'T EXIST!! ***//
      $stateParams.itemId //*** Exists! ***//  
   }
})
Instead, use a resolve statement in the parent route.
$stateProvider.state('contacts.detail', {
   url: '/contacts/:contactId',   
   controller: function($stateParams){      $stateParams.contactId  //*** Exists! ***//
   },
   resolve:{
      contactId: ['$stateParams', function($stateParams){          return $stateParams.contactId;
      }]
   }
}).state('contacts.detail.subitem', {
   url: '/item/:itemId', 
   controller: function($stateParams, contactId){
      contactId //*** Exists! ***//
      $stateParams.itemId //*** Exists! ***//  
   }
})

$urlRouterProvider

$urlRouterProvider has the responsibility of watching $location. When $location changes it runs through a list of rules one by one until a match is found. $urlRouterProvider is used behind the scenes anytime you specify a url in a state configuration. All urls are compiled into a UrlMatcher object (see $urlMatcherFactory below).

$urlRouterProvider会监测$location。当$location发生变化,$urlRouterProvider依据监测规则一个个的检查直到匹配为止。你任何时候在状态配置中指定连接都会在幕后运转$urlRouterProvider。所有连接将会编译为连接匹配对象($urlMatcherFactory 中将会介绍)。

There are several methods on $urlRouterProvider that make it useful to use directly in your module config.

这里有很多关于$urlRouterProvider的使用技巧,这些技巧直接在模块配置中使用堪称利器。


when() for redirection

重定向-when() 

Parameters:

  • what String | RegExp | UrlMatcher The incoming path that you want to redirect.

  • handler String | Function The path you want to redirect your user to.

handler as String

If handler is a string, it is treated as a redirect, and is interpolated according to the syntax of match (i.e. like String.replace() for RegExp, or like a UrlMatcher pattern otherwise).

如果handler 是字符串,他将作为重定向的路径并依照匹配语法进行替换(例如:类似于 String.replace() ,类似于路径匹配模式等等)。

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 as Function

If the handler is a function, it is injectable. It gets invoked if $location matches. You have the option of inject the match object as $match

如果handler为函数,它可注入其他服务。如果$location 匹配成功,调用函数。你可以注入诸如$match服务。

The handler can return:


  • falsy to indicate that the rule didn't match after all, then $urlRouter will continue trying to find another one that matches.

  • 返回错误的值表明未匹配成功,然后$urlRouter会继续匹配其他对象。

  • String, which is treated as a redirect and passed to $location.url()

  • 返回的字符串做为重定向路径传递给$location.url()

  • nothing or any truthy value tells $urlRouter that the url was handled

  • 啥也没有返回,或是返回正确的值,这等于告诉 $urlRouter链接已经被处理了。

Here's the actual code that we use to register state's that have urls behind the scenes.

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

otherwise() for invalid routes

无效路径-otherwise() 

Parameters:

  • path String | Function The url path you want to redirect to or a function rule that returns the url path. The function version is passed two params: $injector and $location.

  • path String | Function 需要重定向的连接路径或返回URL路径的函数规则。函数传递两个参数:$injector and $location

app.config(function($urlRouterProvider){
    // if the path doesn't match any of the urls you configured
    // 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() for custom url handling

自定义url handling-rule()

Parameters:

  • handler Function A function that takes in the $injector and $location services as arguments. You are responsible for returning a valid path as a string.

  • handler函数中传入$injector 和 $location做为参数,你需要返回可用路径的字符串。

app.config(function ($urlRouterProvider) {
   // Here's an example of how you might allow case insensitive urls
   // Note that this is an example, and you may also use 
   // $urlMatcherFactory.caseInsensitive(true); for a similar result.
   $urlRouterProvider.rule(function ($injector, $location) {
        //what this function returns will be set as the $location.url
        var path = $location.path(), normalized = path.toLowerCase();
        if (path != normalized) {
            //instead of returning a new url string, I'll just change the $location.path directly so I don't have to worry about constructing a new url string and so a new state change is not triggered
            $location.replace().path(normalized);
        }
        // because we've returned nothing, no state change occurs
    });
})

$urlMatcherFactory and UrlMatchers

Defines the syntax for url patterns and parameter placeholders. This factory service is used behind the scenes by $urlRouterProvider to cache compiled UrlMatcher objects, instead of having to re-parse url patterns on every location change. Most users will not need to use $urlMatcherFactory directly, however it could be useful to craft a UrlMatcher object and pass it as the url to the state config.

给链接模式和参数占位符定义了语法。这个服务工厂由$urlRouterProvider自动缓存编译链接匹配对象,无需重新解析每个本地更改的链接模式。使用者无需直接使用 $urlMatcherFactory,它会精确匹配链接匹配对象并作为链接传入其中。

Please refer to the comment documentation within the $urlMatcherFactory file to learn more.

学习更多相关知识请参考$urlMatcherFactory file

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章