0%

angular2 路由器使用

路由器使用浏览器的history.pushState进行导航,正因为有它,我们才可以按照期望的样子显示应用内部的url路径。这种风格也就是“html5风格url”。

我们必须往本应用的index.html中添加一个<base href>元素,这样pushState才能正常工作。也就是告诉浏览器,以当前页面为应用的基底。

比如,我们目前的app目录是应用的根目录,可以在index.html文件的head中这样设置<base href="/">

从路由库中导入

路由器在它自己的@angular/router包中,而不是angular的内核中。该路由器是可选服务,如果需要,还可以引入另外的路由库。

在app.module.ts中引入:

1
import { RouterModule, Routes } from '@angular/router';

定义路由

每个带路由的angular应用都有一个Router服务的单例对象,当浏览器的url变化时,路由器会查找对应的路由,并据此决定该显示哪个组件。定义路由的两个基本参数:

  1. path 字符串,标记路径
  2. component 组件,需要实例化的组件

基本用法,例如:

1
2
3
4
5
6
 const appRoutes: Routes = [
{
path: 'crisis-center',
component: CrisisListComponent,
},
];

将链接localhost:4200/crisis-center映射到CrisisListComponent组件。

这里的路由数组appRoutes来描述如何进行导航。每个Route都会把一个URL的path映射到一个组件。

注意path不能以斜杠开头。路由器会解析和构建为最终的url,这样当你在应用的多个试图之间进行导航时,可以使用任意相对滤镜和绝对路径。

路由器使用先匹配者优先的策略来匹配路由,所以具体路由应该放在通配路由前面。

使用路由

RouterModule.forRoot方法来将配置好的路由在应用中使用起来:

1
2
3
4
5
6
7
8
9
imports: [
BrowserModule,
RouterModule.forRoot(
appRoutes,
{
enableTracing: true,
}
),
],

enableTracing属性用来把每个导航生命周期中的事件输出到控制台,便于跟踪。

路由出口

路由出口来告诉浏览器在哪里显示组件,使用指令<router-outlet></router-outlet>。路由器匹配到path的路径之后,会在宿主视图中的RouterOutlet之后显示组件。

路由器链接

我们可以在浏览器url中直接输入地址来跳转页面,那么如何在页面中使用路由?

RouterLink指令让路由器控制一个元素,可以直接赋值为一个字符串进行“一次性绑定”,也可以绑定到一个返回链接参数数组的模板表达式,路由器会把这个表达式解析为一个完整的url。

RouterLinkActive指令可以帮用户在外观上区分出当前选中的“活动”路由,等号右侧的模板表达式包含用空格分隔的一些css类。当与这个关联的路由被激活时,路由器会把一些css类加到这个元素上。

1
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>

路由状态

在导航时的每个生命周期成功完成时,路由器会构建出一个ActivatedRoute组成的树,它表示路由器的当前状态,可以在应用中的任何地方使用Router服务的routerState属性来访问当前的RouterState的值。例如:

1
2
3
4
5
ngOnInit() {
console.log('routerstates', this.router.routerState);
// 可以获得当前导航的url
console.log('routerstates', this.router.routerState.snapshot.url);
}

激活的路由

当前路由的页面的路径url和参数可以通过注入一个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 包含当前路由下所有已激活的子路由。

paramMap为例:

1
2
3
4
5
6
7
this.activatedRouter.paramMap.pipe(
switchMap((params: ParamMap) =>
this.type = params.get('type')
)
).subscribe(() => {
// 参数变更后的操作
});

使用switchMap操作符,可以复用这个组件,也就是可以检测到url中的变量变更后开始一系列操作。

通配符路由

当路由器收到未定义的路由时,会崩溃,所以我们需要考虑如何处理这些无效的url,让我们的应用健壮。

可以添加一个通配符路由来优雅的处理无效的url。通配符路由的path是两个星号(**),他们会匹配任何url,当路由器匹配不上前面定义的任何路由,就会选择这个路由,可以让这个路由导航到自定义的“404”组件,也可以重定向到现有的路由。务必确保它是最后一个路由。

1
2
3
4
{
path: '**',
component: NoFind404Component,
}

默认路由

当我们访问locahost:4200时,由于没有定义到这个路由,所以会匹配到通配符路由,显示404。但是这个是正常且有效的路由,所以我们需要一个默认路由,我们可以添加个路由,把空路径重定向到某个已定义路由。

1
2
3
4
5
{
path: '',
redirectTo: '/heroes',
pathMatch: 'full',
},

重定向路由需要一个pathMatch属性,来告诉路由器如何用url去匹配路由的路径,否则路由会报错。这里需要完整匹配url等于''时才匹配,所以需要把pathMatch设置为true

pathMatch的另一个属性是prefix,这个属性告诉路由器,如果跳转路径是以这个path开头时,就会匹配上这个跳转路由。

路由模块

为了方便扩展,需要将路由单独抽出来称为一个路由模块。将关注点从文件app.module.ts中挪出去。
app/目录下创建路由模块文件app-routing.module.ts,将路由的导入语句和路由的配置以及RouterModule.forRoot()移入这个文件,并添加一个AppRoutingModule类并导出它,以便在AppModule中使用它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { NgModule } from '@angular/core';
import { RouterModule, Routes} from '@angular/router';
import { HeroesComponent } from './heroes/heroes.component';
const appRoutes: Routes = [
{
path: 'heroes',
component: HeroesComponent,
data: {title: 'hero'}
},
];
@NgModule({
imports: [
RouterModule.forRoot(
appRoutes,
{
enableTracing: true,
}
),
],
exports: [
RouterModule
]
})
export class AppRoutingModule { }
码字辛苦,打赏个咖啡☕️可好?💘