在 Angular 中,什么是“路径匹配:完整”,它有什么作用?

新手上路,请多包涵

在这里它使用完整的路径匹配,当我删除这个路径匹配时,它甚至不会加载应用程序或运行项目

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';

import { AppComponent }  from './app.component';
import { WelcomeComponent } from './home/welcome.component';

/* Feature Modules */
import { ProductModule } from './products/product.module';

@NgModule({
  imports: [
    BrowserModule,
    HttpModule,
    RouterModule.forRoot([
      { path: 'welcome', component: WelcomeComponent },
      { path: '', redirectTo: 'welcome', pathMatch: 'full' },
      { path: '**', redirectTo: 'welcome', pathMatch: 'full' }
    ]),
    ProductModule
  ],
  declarations: [
    AppComponent,
    WelcomeComponent
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

原文由 Chanaka Amarasinghe 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 833
2 个回答
RouterModule.forRoot([
      { path: 'welcome', component: WelcomeComponent },
      { path: '', redirectTo: 'welcome', pathMatch: 'full' },
      { path: '**', component: 'pageNotFoundComponent' }
    ])

案例 1 pathMatch:'full' :在这种情况下,当应用程序在 localhost:4200 (或某些服务器)上启动时,默认页面将是欢迎屏幕,因为 url 将是 https://localhost:4200/

如果 https://localhost:4200/gibberish 这将重定向到 pageNotFound 屏幕,因为 path:'**' 通配符

案例2 pathMatch:'prefix'

如果路由有 { path: '', redirectTo: 'welcome', pathMatch: 'prefix' } ,现在这将永远不会到达通配符路由,因为每个 url 都会匹配 path:'' 定义。

原文由 sai amar 发布,翻译遵循 CC BY-SA 4.0 许可协议

虽然在技术上是正确的,但其他答案将受益于对 Angular 的 URL-to-route 匹配的解释。如果您一开始不知道路由器的工作原理,我认为您无法完全(请原谅双关语)理解 pathMatch: full 的作用。


让我们首先定义一些基本的东西。我们将使用此 URL 作为示例: /users/james/articles?from=134#section

  1. 这可能很明显,但让我们首先指出 查询参数( ?from=134 )和片段( #section )在路径匹配中没有任何作用。只有基本 url ( /users/james/articles ) 很重要。

  2. Angular 将 URL 分割成 /users/james/articles 的段,当然是 usersjamesarticles

  3. 路由器配置是具有单个根节点的 结构。每个 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 _完全匹配_。以下是此示例的完成方式:

  1. 遍历根数组,寻找第一个 URL 段的完全匹配 - users
  2. 'products' !== 'users' ,所以跳过那个分支。请注意,我们使用的是相等性检查,而不是 .startsWith().includes() - 只有完整的段匹配计数!
  3. :other 匹配任何值,所以它是匹配的。但是,目标 URL 还没有完全匹配(我们仍然需要匹配 jamesarticles ),因此路由器会寻找孩子。
  • :other 的唯一孩子是 tricks ,即 !== 'james' ,因此不匹配。
  1. Angular 然后回溯到根数组并从那里继续。
  2. 'user' !== 'users ,跳过分支。
  3. 'users' === 'users - 段匹配。但是,这还不是完全匹配,因此我们需要寻找孩子(与步骤 3 相同)。
  • 'permissions' !== 'james' ,跳过它。
  • :userID 匹配任何东西,因此我们有一个匹配 james 段。然而这 仍然 不是完全匹配,因此我们需要寻找一个匹配 articles 的孩子。
    1. 我们可以看到 :userID 有一个子路由 articles ,这给了我们一个完全匹配!因此应用程序呈现 UserArticlesComponent

完整 URL ( 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 会有所不同:

  1. 'users' !== 'users/james/articles - the segment does not match because the path configuration users with pathMatch: full does not match the full URL, which is users/james/articles .
  2. 由于没有匹配,我们跳过了这个分支。
  3. 至此,我们在没有找到匹配项的情况下完成了路由器配置。该应用程序不呈现 _任何内容_。

示例 2

如果我们有这个怎么办:

 {
  path: 'users/:userID',
  component: UsersComponent,
  pathMatch: 'full',
  children: [
    {
      path: 'comments',
      component: UserCommentsComponent,
    },
    {
      path: 'articles',
      component: UserArticlesComponent,
    },
  ],
}

users/:userIDpathMatch: 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,
        },
      ],
    },
  ],
}

在这种情况下:

  1. 'users' === 'users - 段匹配,但 james/articles 仍然不匹配。让我们寻找孩子。
  • 'permissions' !== 'james' 跳过。
  • :userID' 只能匹配单个段,即 james 。但是,它是一个 pathMatch: full 路由,它必须匹配 james/articles (整个剩余的 URL)。它无法做到这一点,因此它不匹配(所以我们跳过这个分支)!
  1. 同样,我们没有找到任何匹配的 URL,应用程序没有呈现 _任何内容_。

您可能已经注意到, pathMatch: full 配置基本上是这样说的:

忽略我的孩子,只匹配我。如果我自己无法匹配所有 剩余 的 URL 段,请继续。

重定向

任何定义了 redirectTo Route --- 都将根据相同的原则与目标 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 ),会发生以下情况:

  1. 'not-found' !== 'users' - 跳过它。
  2. 'users' === 'users' 我们有一个匹配。
  3. 这场比赛有一个 redirectTo: 'not-found' , _立即应用_。
  4. 目标 URL 更改为 not-found
  5. 路由器再次开始匹配,并立即找到 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,
      },
    ],
  },
];

  1. 'not-found' !== 'users' 跳过它。
  2. users 将匹配 URL 的第一段,但路由配置需要 full 匹配,因此跳过它。
  3. 'users/:userID' 匹配 users/jamesarticles 仍然不匹配,但这条路线有孩子。
  • 我们在孩子中找到了 articles 的匹配项。整个 URL 现在匹配,应用程序呈现 UserArticlesComponent

空路径( path: ''

空路径是一种特殊情况,因为它可以匹配 任何 而不“消耗”它(因此它的孩子必须再次匹配该段)。考虑这个例子:

 const routes: Routes = [
  {
    path: '',
    children: [
      {
        path: 'users',
        component: BadUsersComponent,
      }
    ]
  },
  {
    path: 'users',
    component: GoodUsersComponent,
  },
];

假设我们正在尝试访问 /users

  • path: '' 将始终匹配,因此路由匹配。但是,整个 URL 还没有匹配 - 我们仍然需要匹配 users
  • 我们可以看到有一个孩子 users ,它匹配剩余的(也是唯一的!)段,我们有一个完整的匹配。应用程序呈现 BadUsersComponent

现在回到最初的问题

OP使用了这个路由器配置:

 const routes: Routes = [
  {
    path: 'welcome',
    component: WelcomeComponent,
  },
  {
    path: '',
    redirectTo: 'welcome',
    pathMatch: 'full',
  },
  {
    path: '**',
    redirectTo: 'welcome',
    pathMatch: 'full',
  },
];

如果我们导航到根 URL ( / ),路由器将如何解决这个问题:

  1. welcome 不匹配空段,所以跳过它。
  2. path: '' 匹配空段。它有一个 pathMatch: 'full' ,这也很满意,因为我们匹配了整个 URL(它有一个空段)。
  3. 重定向到 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,
  },
];

如果我们导航到 /welcomepath: '**' 将匹配并且重定向到 Welcome 将会发生。从理论上讲,这应该会启动一个无休止的重定向循环,但 Angular 会立即停止(因为我之前提到的保护)并且整个事情都很好。

原文由 Avius 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进