在用户使用应用程序时,Angular
的路由器能让用户从一个视图导航到另外一个视图。html
Angular
的 Router
(即“路由器”)把浏览器中的 URL
看作一个操做指南, 据此导航到一个视图,并能够把参数传给支撑视图的相应组件,帮它决定具体该展示哪些内容。
路由器还在浏览器的历史日志中记录下这些活动,这样浏览器的前进和后退按钮也能照常工做。数组
base href
元素,来告诉路由器该如何合成导航用的 URL
。 须要在index.html
的 <head>
标签下先添加一个 <base>
元素。
src/index.html
浏览器
<base href="/">
复制代码
Angular
的路由器是一个可选的服务,它用来呈现指定的 URL
所对应的视图。 它并非 Angular
核心库的一部分,而是在它本身的 @angular/router
包中。bash
src/app/app.module.ts
app
import { RouterModule, Routes } from '@angular/router';
复制代码
路由器须要先配置才会有路由信息。 下面的例子建立了五个路由定义,并用 RouterModule.forRoot
方法来配置路由器, 并把它的返回值添加到 AppModule
的 imports
数组中。this
src/app/app.module.ts
url
const appRoutes: Routes = [
{ path: 'crisis-center', component: CrisisListComponent },
{ path: 'hero/:id', component: HeroDetailComponent },
{
path: 'heroes',
component: HeroListComponent,
data: { title: 'Heroes List' }
},
{
path:'portal',
loadChildren: './settings/settings.module#SettingsModule'
}
{ path: '',
redirectTo: '/heroes',
pathMatch: 'full'
},
{ path: '**', component: PageNotFoundComponent }
];
@NgModule({
imports: [
RouterModule.forRoot(
appRoutes,
{ enableTracing: true } // <-- debugging purposes only
)
// other imports here
],
...
})
export class AppModule { }
复制代码
这里的路由数组 appRoutes
描述如何进行导航。 把它传给 RouterModule.forRoot
方法并传给本模块的 imports
数组就能够配置路由器。
每一个 Route
都会把一个 URL
的 path
映射到一个组件。
注意,path
不能以斜杠(/)
开头,能够以(../)
开头。spa
第二个路由中的 :id
是一个路由参数的令牌(Token)
。好比 /hero/42
这个 URL
中,“42”
就是 id
参数的值。debug
第三个路由中的 data
属性用来存放于每一个具体路由有关的任意信息。该数据能够被任何一个激活路由访问,并能用来保存诸如 页标题、面包屑以及其它静态只读数据。设计
第四个路由中咱们没有将 ettingsModule
导入到咱们的 AppModule
中,而是经过 loadChildren
属性来告诉 Angular
路由依据 loadChildren
属性配置的路径去加载 SettingsModule
模块。这就是模块懒加载功能的具体应用,当用户访问 /settings/**
路径的时候,才会加载对应的 SettingsModule
模块,这减小了应用启动时加载资源的大小。 另外咱们传递一个字符串做为 loadChildren
的属性值,该字符串由三部分组成:
(1)须要导入模块的相对路径
(2)#
分隔符
(3)导出模块类的名称
第五个路由中的空路径('')
表示应用的默认路径,当 URL
为空时就会访问那里,所以它一般会做为起点。 这个默认路由会重定向到 URL
/heroes
,并显示 HeroesListComponent
。
最后一个路由中的 ** 路径是一个通配符。当所请求的 URL
不匹配前面定义的路由表中的任何路径时,路由器就会选择此路由。 这个特性可用于显示“404 - Not Found”
页,或自动重定向到其它路由。
这些路由的定义顺序是刻意如此设计的。路由器使用先匹配者优先的策略来匹配路由,因此,具体路由应该放在通用路由的前面。在上面的配置中,带静态路径的路由被放在了前面,后面是空路径路由,所以它会做为默认路由。而通配符路由被放在最后面,这是由于它能匹配上每个 URL
,所以应该只有在前面找不到其它能匹配的路由时才匹配它。
若是你想要看到在导航的生命周期中发生过哪些事件,可使用路由器默认配置中的 enableTracing
选项。它会把每一个导航生命周期中的事件输出到浏览器的控制台。 这应该只用于调试。你只须要把 enableTracing: true
选项做为第二个参数传给 RouterModule.forRoot()
方法就能够了。
Routes
是路由配置数组。每一个都有如下属性:
path
是路由匹配的路径。pathMatch
是指定匹配策略的字符串。pathMatch:'full'
表示彻底匹配matcher
定义了路径匹配并取代自定义策略path
和pathMatch
。component
是组件类型。redirectTo
是将替换当前匹配段的url
片断。outlet
是组件应放入的插座的名称。canActivate
控制是否容许进入路由。。canActivateChild
等同 canActivate
,只不过针对是全部子路由。。canDeactivate
控制是否容许离开路由。canLoad
控制是否容许延迟加载整个模块。data
是提供给组件的附加数据,被激活路由访问。resolve
是用于查找数据解析器的DI
令牌的映射。children
是子路由定义的数组。loadChildren
是对延迟加载子路由的引用。注意:路由守卫对于权限控制很是便利,固然其粒度固然只能在页面层级。假若须要对按钮粒度也只能利用指令的方式,而两者的结合能够极大的改善权限控制埋点的代码量。
RouterModule.forChild()
与 Router.forRoot()
方法相似,但它只能应用在特性模块中。
这个功能很是强大,由于咱们没必要在一个地方(咱们的主模块)定义全部路由信息。反之,咱们能够在特性模块中定义模块特有的路由信息,并在必要的时候将它们导入咱们主模块。RouterModule.forChild()
的使用方法以下:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';
export const ROUTES: Routes = [
{
path: 'settings',
component: SettingsComponent,
///settings 设置页面下有 /settings/profile 和 /settings/password 两个页面
children: [
{ path: 'profile', component: ProfileSettingsComponent },
{ path: 'password', component: PasswordSettingsComponent }
]
}
];
@NgModule({
imports: [
CommonModule,
RouterModule.forChild(ROUTES)
],
// ...
})
export class ChildModule {}
复制代码
经过以上示例,咱们知道在主模块和特性模块中,路由配置对象的类型是同样的,区别只是主模块和特性模块中需调用不一样的方法,来配置模块路由。
RouterOutlet
是一个来自路由模块中的指令,它的用法相似于组件。 它扮演一个占位符的角色,用于在模板中标出一个位置,路由器将会把要显示在这个出口处的组件显示在这里。
<router-outlet></router-outlet>
<!-- Routed components go here -->
复制代码
有了这份配置,当本应用在浏览器中的 URL
变为 /heroes
时,路由器就会匹配到 path
为 heroes
的 Route
,并在宿主视图中的RouterOutlet
以后显示 HeroListComponent
组件。
1.路由配置
const routes: Routes = [
{ path: 'news',
component: NewsComponent,
outlet:'let1'
}
{ path: 'news',
component: News2Cmponent,
outlet:'let2'
}]
2.html点击连接
<a routerLink = "[{ outlets: { let1: ['news'] } }]"></a>
<a routerLink = "[{ outlets: { let2: ['news'] } }]"></a
3.html路由出口
<router-outlet name="let1"></router-outlet>
<router-outlet name="let2"></router-outlet>
复制代码
即访问 /news/
时同时加载 NewsComponent
和 News2Cmponent
两个组件
如今,你已经有了配置好的一些路由,还找到了渲染它们的地方,但又该如何导航到它呢?当然,从浏览器的地址栏直接输入 URL
也能作到,可是大多数状况下,导航是某些用户操做的结果,好比点击一个 A
标签。
考虑下列模板:
src/app/app.component.html
<h1>Angular Router</h1>
<nav>
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
<a routerLink="/heroes" routerLinkActive="active">Heroes</a>
</nav>
<router-outlet></router-outlet>
复制代码
a
标签上的 RouterLink
指令让路由器得以控制这个 a
元素。 这里的导航路径是固定的,所以能够把一个字符串赋给 routerLink
(“一次性”绑定)。 routerLink
第一个路径片断能够以 /
,./
或 ../
开头:
若是以 /
开头,路由将从根路由开始查找
若是以 ./
开头或没有使用 /
,则路由将从当前激活路由的子路由开始查找
若是以 ../
开头,路由往上一级查找
若是须要更加动态的导航路径,那就把它绑定到一个返回连接参数数组的模板表达式。 路由器会把这个数组解析成完整的 URL
。
例如使用 ['/team', teamId, 'user', userName, {details: true}]
数组,意味着咱们想要生成一个连接到 /team/11/user/bob;details=true
。
import { Router } from '@angular/router';
// ...
constructor(private router: Router) {}
// ...
this.router.navigate(['/detail', this.news.id])
this.router.navigate([{ outlets: { let2: null }}]);
复制代码
navigateByUrl
方法指向完整的绝对路径
<a routerLink="/user/bob" routerLinkActive="active">Bob</a>
复制代码
RouterLinkActive
指令:当 URL
地址是 /user
或 /user/bob
时,当前的 RouterState
为活动状态,active
类将会被添加到 <a>
标签上。若是 URL
发生变化,则 active
类将自动从 <a>
标签上移除。
路由连接的激活状态会向下级联到路由树中的每一个层级,因此,父子路由连接可能会同时激活。
只有当 URL
与当前 URL
精确匹配时才会激活,能够把 [routerLinkActiveOptions]
绑定为 { exact: true }
表达式。
路由器的当前状态(RouterState
):在导航时的每一个生命周期成功完成时,路由器会构建出一个 ActivatedRoute
组成的树。
你能够在应用中的任何地方用 Router
服务及其 routerState
属性来访问当前的 RouterState
值。
RouterState
中的每一个 ActivatedRoute
都提供了从任意激活路由开始向上或向下遍历路由树的一种方式,以得到关于父、子、兄弟路由的信息。
class MyComponent {
constructor(router: Router) {
const state: RouterState = router.routerState;
const snapshot: RouterStateSnapshot = state.snapshot;
const root: ActivatedRouteSnapshot = snapshot.root;
const child = root.firstChild;
const id: Observable<string> = child.params.map(p => p.id);
//...
}
}
复制代码
该路由的路径和参数能够经过注入进来的一个名叫ActivatedRoute
的路由服务来获取。 它有一大堆有用的信息,包括:
属性 | 说明 |
---|---|
url |
路由路径的 Observable 对象,是一个由路由路径中的各个部分组成的字符串数组。 |
data |
一个 Observable ,其中包含提供给路由的 data 对象。也包含由解析守卫(resolve guard )解析而来的值。 |
paramMap |
一个 Observable ,其中包含一个由当前路由的必要参数和可选参数组成的map 对象。用这个 map 能够获取来自同名参数的单一值或多重值。 |
queryParamMap |
一个 Observable ,其中包含一个对全部路由都有效的查询参数组成的map 对象。 用这个 map 能够获取来自查询参数的单一值或多重值。 |
fragment |
一个适用于全部路由的 URL 的 fragment (片断)的 Observable 。 |
outlet |
要把该路由渲染到的 RouterOutlet 的名字。对于无名路由,它的路由名是 primary ,而不是空串。 |
routeConfig |
用于该路由的路由配置信息,其中包含原始路径。 |
parent |
当该路由是一个子路由时,表示该路由的父级 ActivatedRoute 。 |
firstChild |
包含该路由的子路由列表中的第一个 ActivatedRoute 。 |
children |
包含当前路由下全部已激活的子路由。 |
//获取路由参数
private route: ActivatedRoute,
this.username = this.route
.queryParamMap
.pipe(map(params => this.username = params.username));
复制代码
在每次导航中,Router
都会经过 Router.events
属性发布一些导航事件。这些事件的范围涵盖了从开始导航到结束导航之间的不少时间点。下表中列出了所有导航事件:
路由器事件 | 说明 |
---|---|
NavigationStart |
本事件会在导航开始时触发。 |
RouteConfigLoadStart |
本事件会在 Router 惰性加载 某个路由配置以前触发。 |
RouteConfigLoadEnd |
本事件会在惰性加载了某个路由后触发。 |
RoutesRecognized |
本事件会在路由器解析完 URL ,并识别出了相应的路由时触发 |
GuardsCheckStart| 本事件会在路由器开始 Guard 阶段以前触发。 |
|
ChildActivationStart |
本事件会在路由器开始激活路由的子路由时触发。 |
ActivationStart |
本事件会在路由器开始激活某个路由时触发。 |
GuardsCheckEnd |
本事件会在路由器成功完成了 Guard 阶段时触发。 |
ResolveStart |
本事件会在 Router 开始解析(Resolve )阶段时触发。 |
ResolveEnd |
本事件会在路由器成功完成了路由的解析(Resolve )阶段时触发。 |
ChildActivationEnd |
本事件会在路由器激活了路由的子路由时触发。 |
ActivationEnd |
本事件会在路由器激活了某个路由时触发。 |
NavigationEnd |
本事件会在导航成功结束以后触发。 |
NavigationCancel |
本事件会在导航被取消以后触发。 这多是由于在导航期间某个路由守卫返回了 false 。 |
NavigationError |
这个事件会在导航因为意料以外的错误而失败时触发。 |
Scroll |
本事件表明一个滚动事件。 |
当启用了 enableTracing
选项时,这些事件也同时会记录到控制台中。要想查看对路由导航事件进行过滤的例子,请访问 Angular
中的可观察对象一章的路由器部分
适用于后台管理等须要登陆才能使用的模块
// app/auth.service.ts
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class AuthService implements CanActivate {
canActivate() {
// 这里判断登陆状态, 返回 true 或 false
return true;
}
}
复制代码
// app/app.router.ts
// 增长 CanActivate
import { CanActivate ... } from '@angular/router';
// 配置中增长 canActivate 如:
{ path: 'admin', canActivate:[AuthService] ... }
复制代码
该应用有一个配置过的路由器。 外壳组件中有一个 RouterOutlet
,它能显示路由器所生成的视图。 它还有一些 RouterLink
,用户能够点击它们,来经过路由器进行导航。
下面是一些路由器中的关键词汇及其含义:
路由器部件 | 含义 |
---|---|
Router (路由器) |
为激活的 URL 显示应用组件。管理从一个组件到另外一个组件的导航。ts->this.router.navigateByUrl("/protel") |
RouterModule |
一个独立的 Angular 模块,用于提供所需的服务提供商,以及用来在应用视图之间进行导航的指令。ts->RouterModule.forRoot(Routers数组,ExtraOptions对象) |
Routes (路由数组) |
定义了一个路由数组,每个都会把一个 URL 路径映射到一个组件。ts->[(path:'',componet: ***)] |
Route (路由) |
定义路由器该如何根据 URL 模式(pattern )来导航到组件。大多数路由都由路径和组件类构成。 |
RouterOutlet (路由出口) |
该指令(<router-outlet> )用来标记出路由器该在哪里显示视图。 |
RouterLink (路由连接) |
这个指令把可点击的 HTML 元素绑定到某个路由。点击带有 routerLink 指令(绑定到字符串或连接参数数组)的元素时就会触发一次导航。html-><a [routerLink]="[./order]"></a> |
RouterLinkActive (活动路由连接) |
当 HTML 元素上或元素内的routerLink 变为激活或非激活状态时,该指令为这个 HTML 元素添加或移除 CSS 类。html中 |
ActivatedRoute (激活的路由) |
为每一个路由组件提供的一个服务,它包含特定于路由的信息,好比路由参数、静态数据、解析数据、全局查询参数和全局碎片(fragment )。ts中 |
RouterState (路由器状态) |
路由器的当前状态包含了一棵由程序中激活的路由构成的树。它包含一些用于遍历路由树的快捷方法。 |
连接参数数组 | 这个数组会被路由器解释成一个路由操做指南。你能够把一个RouterLink 绑定到该数组,或者把它做为参数传给Router.navigate 方法。 |
路由组件 | 一个带有RouterOutlet 的 Angular 组件,它根据路由器的导航来显示相应的视图。 |