Angular对路由的支持非常强大,可以实现多种路由模式,本文主要介绍辅助路由。
辅助路由
辅助路由(auxiliary route)是一种特殊的路由,它的主要应用场景是为当前页面添加弹窗,主路由和辅助路由对应的组件同时显示,当关闭辅助路由组件(弹窗)时,主路由仍然保持显示。
实现步骤
创建Project
首先参考这篇创建一个Angular项目。注意从Angular 17
开始,默认就使用Standalone Component
来创建组件了,不在使用NgModule
了。
添加路由配置
打开app.routes.ts
文件,添加路由配置:
1 | export const routes: Routes = [ |
添加router-outlet
在app.component.html
文件中添加router-outlet
:从Angular17开始,可以使用自关闭组件了,也就是说<router-outlet></router-outlet>
可以简化为<router-outlet />
,注意第二个outlet
添加了name
属性,用来给outlet
命名。
1 | <router-outlet /> |
添加book
组件
1 | ng generate component book |
在book
组件的模板文件中添加一个按钮,点击按钮时显示book-detail
组件:
打开book.component.html
,添加如下代码:
1 | <p>book works!</p> |
打开book.component.ts
,添加按钮点击事件处理函数,这里调用navigate
方法来实现路由跳转。注意该方法的第一个参数是数组,如果要跳转到命名的outlet
, 则格式为:
1 | [{outlets: {outlet-name: 'path-name'}}] |
以下代码中: detail
为命名的outlet
,book-detail
为path-name
。
1 | export class BookComponent { |
添加book-detail
组件
1 | ng generate component book-detail |
打开book-detail.component.html
,添加如下代码:
1 | <div class="book-detail"> |
打开book-detail.component.ts
,添加按钮点击事件处理函数:这里将path
设置为null
,表示关闭对应的组件。
1 | export class BookDetailComponent { |
运行项目
1 | ng serve |
打开浏览器,访问http://localhost:4200/book
点击Book Detail
按钮,弹出book-detail
组件,此时路由变华为https://localhost:4200/book(detail:book-detail)
。
- detail: 表示辅助路由的名称,定义在
outlet
属性中。 - book-detail: 表示辅助路由的路径。定义在
router
文件中。
点击弹窗上的关闭按钮,关闭book-detail
组件,路由恢复为http://localhost:4200/book
。
同时显示多个辅助路由。
添加一个book-list
组件,点击Book List
按钮时显示book-list
弹窗。
1 | ng generate component book-list |
打开book-list.component.html
文件,添加如下代码:
1 | <div class="book-list"> |
打开book-list.component.ts
文件,添加如下代码:
1 | export class BookListComponent { |
打开book-list.component.css
添加样式
1 | .book-list { |
打开book.component.html
文件,添加Book List
按钮:
1 | <p>book works!</p> |
打开book.component.ts
文件,添加按钮点击事件处理函数:
1 | openBookList() { |
在app.routes.ts
文件中添加路由配置:
1 | export const routes: Routes = [ |
打开app.component.html
文件,添加Book List
对应的outlet
:
1 | <router-outlet /> |
在次运行项目,依次点击Book List
和Book Detail
按钮,可以同时显示两个弹窗。观察此时路由的变化,注意有多个辅助路由时,按照路由outlet名字的字符串顺序显示,因为detail排在list前面,所以先显示detail,再显示list。无论先点击哪个按钮,路由顺序皆如此。
http://localhost:4200/book(detail:book-detail//list:book-list)
detail
: 表示辅助路由的名称,定义在outlet
属性中。book-detail
: 表示辅助路由的路径。定义在router
文件中。list
: 表示辅助路由的名称,定义在outlet
属性中。book-list
: 表示辅助路由的路径。定义在router
文件中。//
: 用来分隔多个辅助路由。
不更改URL显示辅助路由
默认情况下,点击按钮后,路由会发生变化,URL会显示辅助路由的路径。如果不想更改URL,可以使用skipLocationChange
选项。
在book.component.ts
文件中,添加按钮点击事件处理函数:
1 | openBookList() { |
注意,如果有多个辅助路由,也要在关闭按钮点击事件处理函数中添加skipLocationChange
选项,否则关闭一个弹窗时,另一个弹窗的URL会显示在地址栏中。
1 | closeBookList() { |
再次点击Book List
和Book Detail
按钮,可以看到URL没有发生变化。依次关闭两个弹窗,URL仍然保持不变。
使用routerLink
显示辅助路由
上面的例子中,我们通过点击按钮,并且在按钮事件处理函数中调用navigate
方法来显示辅助路由。也可以使用routerLink
来显示辅助路由。
在app.component.html
文件中,使用routerLink
显示辅助路由:
1 | <a [routerLink]="[{outlets: {list: 'book-list'}}]">Book List</a> |
主路由和辅助路由各自独立
前面提起过,主路由和辅助路由是平级关系,二者可自由变化,互补影响,比如我们可以在book
组件下添加一个子路由book1
,然后在book1
下再添加子路由book2
。
1 | // app.routers.ts |
1 | <!-- book.component.html --> |
1 | <!-- book1.component.html --> |
1 | <!-- book2.component.html --> |
此时点击book-detail
按钮,观察路由变化,辅助路由自动append到主路由后面,无论主路由的层级有多深。
1 | http://localhost:4200/book/book1/book2(detail:book-detail) |
同时显示主路由和辅助路由
主路由的outlet name
是primary
,我们只需在routerLink或者navigate函数中指定primary
即可。
通过routerLink
属性触发(浏览器url:http://localhost:4200/book(detail:book-detail)
)
1 | <a [routerLink]="[{outlets: {primary: 'book', detail: 'book-detail'}}]">Book and detail</a> |
通过router.navigate
方法触发(浏览器url:http://localhost:4200/book(detail:book-detail)
)
1 | this.router.navigate([{outlets: {primary: 'book', detail: 'book-detail'}}]); |
如果主路由对应多级path
,直接指定即可,如下:(浏览器url:http://localhost:4200/book/book1/book2(detail:book-detail)
)
1 | this.router.navigate([{outlets: {primary: 'book/book1/book2', detail: 'book-detail'}}]); |
一次触发多个辅助路由
上面的例子中我们是依次点击按钮来显示辅助路由的,Angular也支持一次触发多个辅助路由,
使用routerLink
可以在routerLink
中同时定义多个辅助路由,在app.component.html
文件中,添加如下代码,当我们点击Book List and Details
按钮时,将同时显示book-list
和book-detail
组件。Url也将变为http://localhost:4200/book(detail:book-detail//list:book-list)
。
1 | <!-- app.component.html --> |
使用navigate
方法
1 | openBookListAndDetail() { |
总结
- 辅助路由的格式:(outletname: path),比如(list:book-list),
list
对应outlet name
,book-list
对应path
。 - 主路由和辅助路由是平级关系,他们的
outlet
要定义在一个文件中。比如上面例子中book和book-list,book-detail三者都是平级关系,所以他们的outlet
都定义在app.component.html
文件中。 outlet
属性中name
用来表示辅助路由的名称,不能包含-
,不能是字符串primary
,否则无法显示。- html文件中如果使用了
routerLink
,那么同时也要定义outlet
,否则无法显示。