[译]Angular-ui 之 Url Routing

时间:2021-10-19 16:53:12

◄ 前一篇 (Multiple Named Views)     下一篇 (The Components) ►

  在你的应用中多数的状态都是基于特定的url地址的。Url Routing机制绝不是在状态机制之上后加的东西,而是一开始就是规划在最初设计方案(译注:angular-ui的设计方案)之中的(在实现url路由的同时独立的保持状态)。下面代码展示了你如何设置一个url:  

Most states in your application will probably have a url associated with them. 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)

Here's how you set a basic url.

原文

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

  现在,当用户访问index.html/contacts的时候,和'contacts’关联的状态就会变成活动的当前状态,主界面中的ui-view也将用处理后的'contacts.html'来替换。反之亦然,如果程序中通过调用transitionTo('contacts')激活

和'contacts'关联的状态,url也将同时被更新为index.html/contacts。

    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. Alternatively, if the user were to transition to the 'contacts' state via transitionTo('contacts') then the url would be updated toindex.html/contacts

原文

URL路由参数(URL Parameters)

基本参数(Basic Parameters)

经常地,url地址都带有我们称之为参数的动态部分。有多种方式来设置参数。一个基本参数的设置代码如下:

Often, URLs have dynamic parts to them which are called parameters. There are several options for specifying parameters. A basic parameter looks like this:

原文

$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.
  • '/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}' - Same as the previous example, but using curly brace syntax.

正则表达式参数(Regex Parameters)

用花括号来指出参数的一个额外好处就是可以给参数设置正则表达式规则。(A bonus to using curly brackets is the ability to set a Regular Expression rule for the parameter:)

// 下面代码将仅仅识别1到8个数字的contactId(原文: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:[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.
  • '/files/{path:.*}' - 将捕获所有以'/files/'开头的url,后面的剩余部分都将是参数path的内容。(原:Matches any URL starting with '/files/' and captures the rest of the path into the parameter 'path'.)
  • '/files/*path' - 同样地,特殊的语法来识别所有内容(原:Ditto. Special syntax for catch all.)

注意:(Warning:)

  • 不要在表达式两侧添加用于捕获的圆括号!ui-route的UrlMatcher将会自动添加,如果你那样做了将会捕获同样内容两次,这将混淆子url的数量。但是你可以用非捕获组"(?:...)"。(原文: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.)
  • 正则表达式中不能使用右斜线作为内容分隔符。(原:Regular expression can't include forward slashes as that's route segment delimiter)
  • 正则路由参数不能是可选的或贪婪的。(原:Route parameters with regular expressions can't be optional or greedy)

查询参数(uery 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"

嵌套状态下的路由(URL Routing for Nested States)

追加路由(默认)(ppended Routes (default))

当连续调用‘.state’设置url路由时,默认的行为是所有子路由的url都会合并为前面添加其父路由url的形式。

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.

原文

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

此时的路由状态将是:(So the routes would become:)

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

绝对路由(^)(Absolute Routes (^))

如果想要使用绝对url匹配,只需要在原url字符串前面加上符号'^'即可。

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

原文

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

此时的路由匹配将是:(So the routes would become:)

  • 'contacts' state matches "/contacts"
  • 'contacts.list' state matches "/list". The urls were not combined because^ was used.

$stateParams Service

就像你在前面看到的,$stateParams服务是一个对象,每个url参数都会作为此对象的一个属性。$stateParams将以完美的方式为你的controller或者其他服务提供url参数。

注意:$stateParams服务是特定于不同的状态控制器作用范围之下,因此只有导航到了相应的url,对应该url的参数才是可获得的。

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.

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.

原文

// 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' }

关于$stateParams的重点内容(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.

原文

$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! ***//
}
})

如果想访问父路由中的参数怎么办?只要在父路由中设置'resolve'对象即可。(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 服务负责监视$location的变化。当 $location发生改变,它将遍历路由列表直到发现符合规则的路由。任何时候,只要你在状态配置中指定了url,$urlRouterProvider就会在后台起作用。所有的url都将被编译为UrlMatcher对象(参见后面的$urlMatcherFactory部分)。

$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).

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

原文

when() for redirection

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

当handler参数是一个字符串时,它会作为重定向路径对待,url替换时使用类似正则表达式match方法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).

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).

原文

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

如果给出的handler是一个函数,它将是可注入的。如果 $location符合此路由,函数将被调用。你可以注入match对象作为参数$match。

函数的返回值可以是:

  • false 表示最终判断不符合路由规则,此时$urlRouter将继续查找其他符合的路由项目
  • 一个字符串,这个字符串将被作为重定向路径对待并传递给$location.url()函数
  • 不返回任何值 或者 任何相当于true 的值,这表示告诉$urlRouter该url已经处理

下面是背后我们用来注册拥有url属性的状态路由的实际代码。

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

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.
a String, which is treated as a redirect and passed to $location.url()
nothing or any truthy value tells $urlRouter that the url was handled 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)

Parameters:

  • path String | Function The url path you want to redirect to or a function that returns the url path. The function version is passed two params:$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

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.
app.config(function ($urlRouterProvider) {
// Here's an example of how you might allow case insensitive urls
$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 和 UrlMatchers

定义了url模式和参数的占位符的语法。$urlRouterProvider作为背后的工厂服务缓存了编译后的UrlMatcher对象,因此不用再location变化时重新分析编译路由的url。 大多数用户不需要直接使用$urlMatcherFactory对象, 然而,在需要将UrlMatcher对象替代url字符串传递给状态配置时,工厂对象是很有用的。

请参考文档中 $urlMatcherFactory file 部分的注释内容以获得更多知识。

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.

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

原文

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

◄ 上一篇 (Multiple Named Views)     下一篇 (The Components) ►