Angular V12 文档学习与整理(四) - 路由
创建
- 创建带路由的应用:
ng new routing-app --routing
:
这个 –routing
的意思就是立即为此 app 配置路由, 这会在应用的根模块(默认是AppModule
)中添加一个路由模块(AppRoutingModule
),并设置好基本的路由配置文件。
- 将路由模块导入到
app.module
- 在
app-routing.module
中声明routes: Routes
1
2
3
4
const routes: Routes = [
{ path: 'first-component', component: FirstComponent },
{ path: 'second-component', component: SecondComponent },
];
- 将路由应用到项目
1
2
3
4
5
6
7
8
9
10
<h1>Angular Router App</h1>
<!-- This nav gives you links to click, which tells the router which route to use (defined in the routes constant in AppRoutingModule) -->
<nav>
<ul>
<li><a routerLink="/first-component" routerLinkActive="active">First Component</a></li>
<li><a routerLink="/second-component" routerLinkActive="active">Second Component</a></li>
</ul>
</nav>
<!-- The routed views render in the <router-outlet>-->
<router-outlet></router-outlet>
RouterModule.forRoot
方法用于在Angular应用的根模块中配置路由。这个方法接受一个路由定义数组(Routes
)作为参数,并返回一个配置了路由的模块。
- 参数:路由定义数组
Routes
。每个路由定义包含一个路径(path
)、一个组件(component
),以及可选的子路由(children
)、路由守卫(canActivate
)、懒加载模块(loadChildren
)等。 - 返回值:一个配置了路由的模块,这个模块应被导入到应用的根模块中。
路由的顺序
路由的顺序很重要,因为 Router
在匹配路由时使用“先到先得”策略,所以应该在不那么具体的路由前面放置更具体的路由。首先列出静态路径的路由,然后是一个与默认路由匹配的空路径路由。通配符路由是最后一个,因为它匹配每一个 URL,只有当其它路由都没有匹配时,Router
才会选择它。
路由传值
你可以使用 ActivatedRoute 接口, ActivatedRoute
是一个服务,它提供了关于与当前路由有关的信息,比如路由参数、静态数据、URL等。
- 获取路由参数:如果你的路由路径定义了参数(比如
/product/:id
),你可以使用ActivatedRoute
来获取这些参数的值。 - 获取查询参数和片段:你可以获取到URL的查询参数(即URL中
?
后面的部分)和片段(即URL中#
后面的部分)。 - 获取路由的静态数据:可以访问通过路由配置传递给路由的静态数据。
- 观察路由和参数的变化:
ActivatedRoute
提供了若干Observable对象,你可以订阅这些Observable以响应路由或参数的变化。
- 把
ActivatedRoute
和ParamMap
导入到组件。 - 通过把
ActivatedRoute
的一个实例添加到你的应用的构造函数中来注入它:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
styleUrls: ['./product-detail.component.css']
})
export class ProductDetailComponent implements OnInit {
id: string;
constructor(private route: ActivatedRoute) { } // 注入 ActivatedRoute 实例
ngOnInit(): void {
// 使用ActivatedRoute
}
}
- 获取参数的两种方式: 使用
ActivatedRoute
的snapshot
属性或params
Observable来获取路由参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
// snapshot
ngOnInit(): void {
this.id = this.route.snapshot.paramMap.get('id');
}
// params (Observable 对象)
ngOnInit(): void {
this.route.params.subscribe(params => {
this.id = params['id'];
});
}
- 获取查询数据
1
2
3
4
5
6
7
8
9
10
11
// snapshot
ngOnInit(): void {
let page = this.route.snapshot.queryParamMap.get('page');
}
// queryParams
ngOnInit(): void {
this.route.queryParams.subscribe(queryParams => {
let page = queryParams['page'];
});
}
总结
ActivatedRoute
是Angular路由系统的一部分,它允许你访问当前路由的信息,如参数、查询参数、URL片段等。
通配符路由
通配符路由(Wildcard Route)在Angular路由系统中用于匹配那些没有对应到任何其他路由的URL路径。它通常用作捕获所有未知或未处理的路由请求,比如显示一个404错误页面,或者将用户重定向到应用的某个默认页面, 以**
的方式告诉 Angular 这是一个通配符路由。
1
2
3
4
5
6
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'products', component: ProductsComponent },
// 其他路由配置...
{ path: '**', component: PageNotFoundComponent } // 通配符路由,用于匹配所有未知的路径
];
路由重定向
要设置重定向,请使用重定向源的 path
、要重定向目标的 component
和一个 pathMatch
值来配置路由,以告诉路由器该如何匹配 URL。
1
2
3
4
5
6
const routes: Routes = [
{ path: 'first-component', component: FirstComponent },
{ path: 'second-component', component: SecondComponent },
{ path: '', redirectTo: '/first-component', pathMatch: 'full' }, // redirect to `first-component`
{ path: '**', component: PageNotFoundComponent }, // Wildcard route for a 404 page
];
编程式导航
1
2
3
4
goToItems() {
this.router.navigate(['items'], { relativeTo: this.route });
}
查询查询参数与片段
在Web开发中,访问查询参数和片段(URL中的?key=value
结构和#fragment
部分)是一种获取从URL传递的数据的常见方式。
在Angular中,你可以通过ActivatedRoute
服务来访问当前路由的查询参数和片段。ActivatedRoute
提供了queryParams
和fragment
的Observable,你可以订阅这些Observable以响应URL的变化。
特性路由模块和主路由模块的结合
将特性路由模块与主路由模块结合起来,主要用于组织和划分应用的不同功能区域,提高模块化和可维护性。这通常涉及到特性模块的懒加载,从而实现按需加载特性模块,优化应用启动时间和性能。下面我将说明如何将特性路由模块与主路由模块结合起来,使用懒加载的方式。
1. 定义特性路由模块
首先,你需要创建一个特性模块并为其定义路由。这里以一个名为ProductsModule
的特性模块为例,该模块包含产品列表的路由。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// products.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { ProductListComponent } from './product-list/product-list.component';
const routes: Routes = [
{ path: '', component: ProductListComponent }
];
@NgModule({
declarations: [ProductListComponent],
imports: [
CommonModule,
RouterModule.forChild(routes) // 使用forChild来定义特性路由
]
})
export class ProductsModule { }
2. 配置主路由模块以实现懒加载
在应用的主路由模块(通常是AppRoutingModule
),你将通过特定的语法来配置懒加载的路由,指向你的特性模块。注意,路径中不再直接引用组件,而是使用loadChildren
函数来指定模块文件和模块类名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{
path: 'products',
loadChildren: () => import('./products/products.module').then(m => m.ProductsModule)
},
// 其他路由配置...
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule] // 重新导出RouterModule,使其指令在AppModule中可用
})
export class AppRoutingModule { }
在这个例子中,当用户访问/products
路径时,ProductsModule
将会被懒加载。loadChildren
方法接受一个箭头函数,这个函数动态导入特性模块,并返回一个Promise
,该Promise
解析为模块对象,然后使用.then(m => m.ProductsModule)
来指定需要加载的模块。
3. 确保AppModule导入AppRoutingModule
最后,确保你的根模块AppModule
已经导入了AppRoutingModule
,这样主路由配置才会生效。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule // 主路由模块导入
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
通过这种方式,特性路由模块(和它们的路由)与主路由模块结合到一起,实现了功能区域的模块化和路由的懒加载。这种模式对于构建大型和性能优化的Angular应用至关重要。
路由守卫
路由守卫 (Route Guards) 是一种用来控制导航流程的机制, 可以在路由激活, 离开的时候执行某些逻辑, 可以用来执行权限检查, 预先加载组件数据, 以及判断是否离开当前页面
有四种类型的路由守卫:
CanActivate
:决定是否可以导航到某个路由。CanActivateChild
:决定是否可以导航到某个子路由。CanDeactivate
:决定是否可以离开当前路由。Resolve
:在路由激活之前获取路由数据。CanLoad
:决定是否可以异步加载某个特性模块。
要想创建一个守卫, 就要在一个服务里面实现守卫的接口
export class AuthGuard implements CanActivate {}
然后实现细节
1
2
3
4
5
6
7
8
9
10
11
12
13
constructor(private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
const isAuthenticated = // ... 检查用户是否认证
if (!isAuthenticated) {
this.router.navigate(['/login']); // 如果用户未认证,重定向到登录页面
return false;
}
return true;
}
进一步要去配置守卫:
1
2
3
4
5
6
7
const routes: Routes = [
{
path: 'secure',
canActivate: [AuthGuard], // 在这里使用
loadChildren: () => import('./secure/secure.module').then(m => m.SecureModule)
}
];
CanActivateChild
- 用途:
CanActivateChild
用来决定是否可以导航到某个父路由的子路由。 - 工作方式:它在父路由层级上配置,当尝试导航到父路由的任何子路由时会被触发。与
CanActivate
相比,CanActivateChild
提供了在父路由级别统一管理对子路由访问控制的能力。
懒加载
loadChildren: () => import('./secure/secure.module').then(m => m.SecureModule)
这是Angular 实现懒加载的一种方式, 懒加载是一种性能优化技术, 允许应用按需加载特定的模块, 只有用户在实际需要访问的时候才会被加载。
loadChildren
:这是Angular路由配置中的一个属性,用来指定一个模块懒加载的方式,loadChildren
的值是一个返回模块类的Promise
。() =>
:这部分是一个箭头函数(Lambda表达式),它是JavaScript的一个特性,允许你定义匿名函数。这里它作为loadChildren
的值,表示路由被访问时要执行的加载操作。import('./secure/secure.module')
:这是动态import
语句,用于动态加载模块。这是一个JavaScript的提案,目前已经得到了广泛支持。它返回一个`Promise`对象,这个对象解析为一个包含所有模块导出的对象。.then(m => m.SecureModule)
:import
语句返回的Promise
解析完成后,.then()
方法会被调用,m
代表模块导出的对象。这里我们从这个对象中获取SecureModule
模块,并将它返回给Angular路由系统。
这种模式不仅适用于Angular,也是现代JavaScript应用中广泛使用的模块动态加载技术,它允许应用更加灵活地控制资源的加载
Comments powered by Disqus.