尽管在技术上是正确的,但其他答案将从对Angular的URL到路由匹配的解释中受益。我不认为您一开始不了解pathMatch: full
路由器的工作原理,您完全无法理解。
让我们首先定义一些基本的东西。我们将以以下网址为例:/users/james/articles?from=134#section
。
显而易见,但是首先让我们指出查询参数(?from=134
)和片段(#section
)在路径匹配中不起作用。仅基本网址(/users/james/articles
)很重要。
Angular将URL分成多个段。的片段/users/james/articles
,当然,users
,james
和articles
。
路由器配置是具有单个根节点的树形结构。每个Route
对象都是一个节点,该节点可能具有children
节点,而节点又可能具有其他children
节点或叶节点。
路由器的目标是从根节点开始查找路由器配置分支,该分支将完全匹配URL的所有(!!!)段。这很关键!如果Angular找不到可以与整个 URL 匹配的路由配置分支- 不能多也不能少 -它不会呈现任何内容。
例如,如果您的目标URL是,/a/b/c
但路由器只能匹配/a/b
或/a/b/c/d
,则没有匹配,应用程序将不会呈现任何内容。
最后,带有的路由的redirectTo
行为与常规路由略有不同,在我看来,它们将是任何人真正想要使用的唯一地方pathMatch: full
。但是我们稍后再讲。
默认(prefix
)路径匹配
该名称背后的原因prefix
是,这样的路由配置将检查配置path
的路由是否为其余URL段的前缀。但是,路由器只能匹配完整的网段,这使命名有些混乱。
不管怎么说,这是我们的根级路由器配置:
const routes: Routes = [
{
path: 'products',
children: [
{
path: ':productID',
component: ProductComponent,
},
],
},
{
path: ':other',
children: [
{
path: 'tricks',
component: TricksComponent,
},
],
},
{
path: 'user',
component: UsersonComponent,
},
{
path: 'users',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
},
];
请注意,Route
这里的每个对象都使用默认的匹配策略prefix
。这一战略意味着在整个配置树,并尝试将路由器通过迭代来匹配它的目标URL 逐段直到URL是完全匹配的。对于此示例,将执行以下操作:
- 遍历根数组,查找与第一个URL段-完全匹配的对象
users
。
'products' !== 'users'
,因此跳过该分支。请注意,我们使用的是相等性检查,而不是使用- .startsWith()
或.includes()
-只有完整的细分受众群匹配计数!
:other
匹配任何值,因此是匹配项。但是,目标URL尚未完全匹配(我们仍然需要匹配james
和articles
),因此路由器会寻找子代。
- 唯一的孩子
:other
就是tricks
,这是!== 'james'
,因此不匹配。
- 然后,Angular返回到根数组并从那里继续。
'user' !== 'users
,跳过分支。
'users' === 'users
-细分匹配。但是,这还不是完全匹配,因此我们需要寻找孩子(与第3步相同)。
'permissions' !== 'james'
, 跳过它。
:userID
匹配任何东西,因此我们有一个匹配james
段。但是,这仍然不是完全匹配,因此我们需要寻找一个匹配的孩子articles
。
- 我们可以看到其中
:userID
有一条子路线articles
,这给了我们一个完整的比赛!因此,应用程序呈现UserArticlesComponent
。
完整网址(full
)匹配
例子1
现在想象一下users
路由配置对象如下所示:
{
path: 'users',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
注意的用法pathMatch: full
。如果是这种情况,步骤1-5将相同,但是步骤6将有所不同:
'users' !== 'users/james/articles
-段并没有匹配,因为路径配置users
有pathMatch: full
不匹配的完整的URL,这是users/james/articles
。
- 由于没有匹配项,因此我们跳过此分支。
- 至此,我们没有找到匹配项就到达了路由器配置的结尾。该应用程序不呈现任何内容。
例子2
如果我们改用这个怎么办:
{
path: 'users/:userID',
component: UsersComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
}
users/:userID
pathMatch: full
仅具有匹配项,users/james
因此再次成为不匹配项,应用程序不呈现任何内容。
例子3
让我们考虑一下:
{
path: 'users',
children: [
{
path: 'permissions',
component: UsersPermissionsComponent,
},
{
path: ':userID',
component: UserComponent,
pathMatch: 'full',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
],
}
在这种情况下:
'users' === 'users
-细分匹配,但james/articles
仍然不匹配。让我们找孩子。
'permissions' !== 'james'
-跳过。
:userID'
只能匹配一个细分受众群,即james
。但是,这是一条pathMatch: full
路线,并且必须匹配james/articles
(整个剩余URL)。它无法做到这一点,因此不是匹配项(因此我们跳过此分支)!
- 同样,我们找不到与URL匹配的任何内容,并且应用程序未呈现任何内容。
您可能已经注意到,pathMatch: full
配置基本上是这样说的:
忽略我的孩子,只匹配我。如果我自己无法匹配所有剩余的 URL段,请继续。
重新导向
Route
定义为a的任何对象都redirectTo
将根据相同原则与目标URL匹配。唯一的区别是,段匹配后立即应用重定向。这意味着,如果重定向路由使用默认prefix
策略,则部分匹配足以导致重定向。这是一个很好的例子:
const routes: Routes = [
{
path: 'not-found',
component: NotFoundComponent,
},
{
path: 'users',
redirectTo: 'not-found',
},
{
path: 'users/:userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
];
对于我们的初始URL(/users/james/articles
),将发生以下情况:
'not-found' !== 'users'
- 跳过它。
'users' === 'users'
-我们有一场比赛。
- 此匹配具有一个
redirectTo: 'not-found'
,将立即应用。
- 目标URL更改为
not-found
。
- 路由器再次开始匹配,并立即找到匹配项
not-found
。该应用程序渲染NotFoundComponent
。
现在考虑如果该users
路线还具有以下情况pathMatch: full
:
const routes: Routes = [
{
path: 'not-found',
component: NotFoundComponent,
},
{
path: 'users',
pathMatch: 'full',
redirectTo: 'not-found',
},
{
path: 'users/:userID',
children: [
{
path: 'comments',
component: UserCommentsComponent,
},
{
path: 'articles',
component: UserArticlesComponent,
},
],
},
];
'not-found' !== 'users'
- 跳过它。
users
会匹配URL的第一段,但是路由配置需要full
匹配,因此将其跳过。
'users/:userID'
火柴users/james
。articles
仍不匹配,但该路线有孩子。
- 我们
articles
在孩子们中找到了匹配。现在,整个URL都已匹配,并且应用程序呈现UserArticlesComponent
。
空路径(path: ''
)
空路径是一种特殊情况,因为它可以匹配任何段而无需“消耗”它(因此,子级必须再次匹配该段)。考虑以下示例:
const routes: Routes = [
{
path: '',
children: [
{
path: 'users',
component: BadUsersComponent,
}
]
},
{
path: 'users',
component: GoodUsersComponent,
},
];
假设我们正在尝试访问/users
:
path: ''
将始终匹配,因此路由匹配。但是,整个URL尚未匹配-我们仍然需要匹配users
!
- 我们可以看到有一个child
users
,它与其余(唯一!)段匹配,并且我们有一个完全匹配项。该应用程序渲染BadUsersComponent
。
现在回到原始问题
OP使用了以下路由器配置:
const routes: Routes = [
{
path: 'welcome',
component: WelcomeComponent,
},
{
path: '',
redirectTo: 'welcome',
pathMatch: 'full',
},
{
path: '**',
redirectTo: 'welcome',
pathMatch: 'full',
},
];
如果我们导航到根URL(/
),则路由器将解决以下问题:
welcome
与空段不匹配,请跳过它。
path: ''
匹配空段。它有一个pathMatch: 'full'
,当我们匹配整个URL(它有一个空段)时,也会满足要求。
- 重定向到
welcome
发生,应用程序呈现WelcomeComponent
。
如果没有pathMatch: 'full'
呢?
实际上,人们会期望整个事情的行为完全相同。但是,Angular显式地阻止了这种配置({ path: '', redirectTo: 'welcome' }
),因为如果将其放在Route
上面welcome
,则从理论上讲它将创建一个无限循环的重定向。因此Angular只会抛出一个错误,这就是为什么该应用程序根本无法运行的原因!(https://angular.io/api/router/Route#pathMatch)
这确实没有太大意义,因为Angular实施了防止无限重定向的保护-它仅在每个路由级别运行一次重定向。
那path: '**'
呢
path: '**'
将完全匹配任何具有(af/frewf/321532152/fsa
或不带有)的项(匹配项)pathMatch: 'full'
,因此使用此配置选项毫无意义。
另外,由于它匹配所有内容,因此也包含了根路径,这{ path: '', redirectTo: 'welcome' }
在此设置中变得多余。
有趣的是,具有以下配置非常好:
const routes: Routes = [
{
path: '**',
redirectTo: 'welcome'
},
{
path: 'welcome',
component: WelcomeComponent,
},
];
如果我们导航到/welcome
,path: '**'
将是一个匹配项,并且将发生重定向到welcome。这应该会启动一个无限循环的重定向,但是Angular会立即停止该重定向,并且整个过程都可以正常工作。