编辑
我写了一篇文章,详细介绍了Angular 11附带的新修复:
Angular Router: empty paths, named outlets and a fix that came with Angular 11
.
太长,读不下去了
Working demo.
详细说明
为什么它一开始不起作用
A.
TLRD
因为,具有(嵌套)空路径的命名出口并不总是
打得好
(至少在旧版本中)。这就是其中之一。
首先,重要的是要提到Angular Router如何处理路由及其变化。例如,它通过一个名为
UrlTree
1.
.UrlTree可被视为
反序列化版本
URL的名称,它是一个字符串。给予
UrlTree
,路由配置数组将基于此路径遍历(以DFS方式)
UrlTree
.
UrlTree的根是另一个结构,
UrlSegmentGroup
:
constructor(
/** The URL segments of this group. See `UrlSegment` for more information */
public segments: UrlSegment[],
/** The list of children of this group */
public children: {[key: string]: UrlSegmentGroup}) {
forEach(children, (v: any, k: any) => v.parent = this);
如您所见,它类似于一个规则的树结构。从中选择一段
segments
数组包含
path
(例如
'crisis-center'
)以及给定路径的矩阵参数。至于
children
属性,其键是
门店名称
(例如
'test'
)这些值是
UrlSegmentGroup
实例。通过使用这些结构,Angular Router可以表示URL字符串,并且可以提供许多特性和定制。
给定来自的路由配置
crisis-center-routing.module.ts
:
const crisisCenterRoutes: Routes = [
{
path: '', // (1)
component: CrisisCenterComponent,
children: [
{
path: '', // (2)
component: CrisisListComponent,
children: [
{
path: ':id', // (3)
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
]
}
];
一
UrlTree
将路由配置对象与
path: ':id'
看起来是这样的:
// Note: For simplicity, I've only used the `path` to represent the `segments` property
UrlTree {
// UrlSegmentGroup
root: {
children: {
primary: {
children: {
primary: {
children: {
test: {
children: {}
segments: [1], // Matches (3)
}
},
segments: [''], // Matches (1) and (2)
}
}
segments: ['crisis-center'],
}
}
segments: [],
}
}
注意:插座的默认名称为
'primary'
.
上述UrlTree可通过以下方式实现:
<a [routerLink]="['/crisis-center', { outlets: { primary: ['', { outlets: { test: [crisis.id] } }] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
虽然上述方法在理论上应该有效,但事实并非如此。这是因为
''
不是
消耗
当这种情况发生时
primary
将选择出口。更具体地说
''
从…起
primary: ['' ...
将与
(1)
,但第二个
''
(来自
(2)
)不会被吃掉的。
然而,这似乎
to be fixed in Angular v12
:
// At this point, not all paths of the `segment` array have been consumed.
// This time, the route's outlet is taken into account.
const matchedOnOutlet = getOutlet(route) === outlet;
const expanded$ = this.expandSegment(
childModule, segmentGroup, childConfig, slicedSegments,
matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
但是
this
过去是这样的:
// At this point, not all paths of the `segment` array have been consumed.
// As you can see, it always chooses the `primary` outlet
const expanded$ = this.expandSegment(
childModule, segmentGroup, childConfig, slicedSegments, PRIMARY_OUTLET, true);
由于您是旧版本,我们需要找到另一种方法。
当前的方法也会发生类似的情况:
<a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
但这一次导航将不会成功,因为插座之间会出现不匹配。它最终会失败
(2)
,路线的出口在哪里
主要的,重要的
,但电源插座根据电流
UrlSegmentGroup
那一刻是
test
.
解决办法
首先,我注意到
CrisisCenterComponent
没什么作用:
<h2>CRISIS CENTER</h2>
<router-outlet></router-outlet>
所以,我们要把它处理掉。这就是我们将得到的:
危机中心路线。单元ts
:
const crisisCenterRoutes: Routes = [
{
// path: '',
// component: CrisisCenterComponent,
// children: [
// {
path: '',
component: CrisisListComponent,
children: [
{
path: ':id',
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
// ]
// }
]
现在,自从
CrisisListComponent
作为容器,我们可以进行以下更换:
危机中心路线。单元ts
:
const crisisCenterRoutes: Routes = [
{
// path: '',
// component: CrisisCenterComponent,
// children: [
// {
// path: '',
// component: CrisisListComponent,
// children: [
// {
path: ':id',
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
component: CrisisCenterHomeComponent
}
// ]
// }
// ]
// }
]
应用程序路由。单元ts
{
path: 'crisis-center',
loadChildren: () =>
import('./crisis-center/crisis-center.module').then(
mod => mod.CrisisCenterModule
),
data: { preload: true },
// !
component: CrisisListComponent
},
所以,不会有额外的
''
(正如我们所见,这有时会导致问题)匹配。
和
routerLink
在视图中,将保持不变:
<[routerLink]=“[{outlets:{test:[crisis.id]}}]”>
<span class=“徽章”>{{crisis.id}</span>{{crisis.name}
</a>
作为旁注,现在当您选择一个危机中心时
CrisisCenterHomeComponent
也将是活跃的。如果要避免这种情况,可以执行以下操作:
危机中心路线。单元ts
:
/* ... */
{
path: ':id'
component: CrisisDetailComponent,
canDeactivate: [CanDeactivateGuard],
resolve: {
crisis: CrisisDetailResolverService
},
outlet: 'test'
},
{
path: '',
// Uncomment this if you want these 2 Route objects
// to be mutually exclusive(either one of them, not both at the same time)
pathMatch: 'full',
component: CrisisCenterHomeComponent
}
/* ... */
1:
Angular Router: Getting to know UrlTree, ActivatedRouteSnapshot and ActivatedRoute
如果您想了解更多有关Angular Router及其内部工作/功能的信息,我建议您: