【问题标题】:In Angular, What is 'pathmatch: full' and what effect does it have?在 Angular 中,什么是“路径匹配:完整”,它有什么作用?
【发布时间】:2017-03-24 05:43:23
【问题描述】:

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

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 { }

【问题讨论】:

    标签: angular typescript angular-router


    【解决方案1】:
    RouterModule.forRoot([
          { path: 'welcome', component: WelcomeComponent },
          { path: '', redirectTo: 'welcome', pathMatch: 'full' },
          { path: '**', component: 'pageNotFoundComponent' }
        ])
    

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

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

    案例 2 pathMatch:'prefix':

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

    【讨论】:

    • 你好,谢谢你对这个例子的清楚解释,但是你能举一个例子,用另一种类型的路线来说明清楚吗? (例如使用带有子路线等的示例。)。谢谢
    • 非常好的解释,先生,但你能告诉我如何配置 2 种不同的布局吗?比如内部布局和外部布局>
    • 我无法复制Case 2。这是example,我希望第一条路线匹配所有内容,但事实并非如此。我问this question试图解释一下
    【解决方案2】:

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


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

    1. 这可能很明显,但我们首先要指出,查询参数 (?from=134) 和片段 (#section) 在路径匹配中不起任何作用。只有基本网址 (/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 - 由于路径配置 userspathMatch: full 不匹配完整的 URL,即 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,并且应用程序呈现 nothing

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

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

    重定向

    任何定义了 redirectToRoute 都将根据相同的原则与目标 URL 进行匹配。此处唯一的区别是 只要 segment 匹配 就会应用重定向。这意味着如果重定向路由使用默认的 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. 目标网址更改为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: '')

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

    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 会立即停止(因为我之前提到的保护)并且整个事情运行良好。

    【讨论】:

    • 我对完整路径有点困惑。您在完整 URL 匹配示例 3 中提到 Ignore my children and only match me. If I am not able to match all of the remaining URL segments myself, then move on. 在重定向部分的完整路径匹配中您提到 We find a match for articles in the children. The whole URL is now matched and the application renders UserArticlesComponent. 根据我的理解,它在 Reidrect 中也不应该匹配?
    • 记录在案 - 我自己想出了ignore my children 的解释。怀疑这是 Angular 开发人员如何看待它,但它pathMatch: 'full' 的原则之一。因此,在您所指的重定向示例中,请注意 pathMath: 'full' 应用于第二条路由 (path: 'users'),因此 not 匹配。匹配的路由是path: 'users/:userID',不使用pathMatch: 'full',照常工作。所以它首先匹配users/james,然后我们在它的孩子中寻找articles(再一次,它不使用pathMatch: 'full')。
    • 我在What if there was no pathMatch: 'full'? 部分迷路了。如果/ 匹配{ path: '', redirectTo: 'welcome' } 并重定向到welcome 并同时将URL 更改为welcome,为什么它会创建一个无限循环?为什么它不会渲染 WelcomeComponent?
    • 太棒了!很少有人会如此深入,并涵盖所讨论概念的如此多方面。很详细的回答。谢谢!
    • 我见过的路由的最佳解释 ;-)
    【解决方案3】:

    pathMatch = 'full' 在 URL 匹配的其余不匹配段是前缀路径时导致路由命中

    pathMatch = 'prefix' 告诉路由器在剩余 URL开始 与重定向路由的前缀路径时匹配重定向路由。

    参考:https://angular.io/guide/router#set-up-redirects

    pathMatch: 'full'表示,整个URL路径需要匹配,被路由匹配算法消耗。

    pathMatch: 'prefix' 表示选择路径与 URL 开头匹配的第一个路由,但随后路由匹配算法会继续搜索与其余 URL 匹配的匹配子路由。

    【讨论】:

      【解决方案4】:

      路径匹配策略,'prefix' 或 'full' 之一。默认为“前缀”。

      默认情况下,路由器从左侧检查 URL 元素以查看 URL 是否与给定路径匹配,并在匹配时停止。例如,'/team/11/user' 匹配 'team/:id'。

      路径匹配策略“完整”匹配整个 URL。在重定向空路径路由时这样做很重要。否则,由于空路径是任何 URL 的前缀,即使导航到重定向目标,路由器也会应用重定向,从而创建无限循环。

      来源:https://angular.io/api/router/Route#properties

      【讨论】:

      • 这个解释(在给出的解释中)在我看来是最简单也最容易理解的。
      【解决方案5】:

      Angular 的默认行为是:所有路由的 {pathMatch: 'prefix'}。

      现在,让我们看看两者有什么区别:

      如果 pathMatch: 'prefix' => Angular 将在路由数组中搜索路径的前缀(在 URL 中)。

      如果 pathMatch: 'full' => Angular 将在路由数组中搜索确切的路径(在 URL 中)。

      【讨论】:

        【解决方案6】:

        想象一下以下网址:

        example.com/main/anything.
        
        • 案例1中,它将重定向到ErrorPage。

        • 案例 2 中,它将重定向到 MainPage。


        案例 1:(我们将 pathMatch 定义为 'full')

        const routes: Routes = [
          {path: '', component: MainPageComponent},
          {path: 'main', redirectTo: '', pathMatch: 'full'},
          {path: '**', component: ErrorPageComponent}
        ];
        

        案例2:(我们没有定义pathMatch,默认是pathMatch: 'prefix')

        const routes: Routes = [
          {path: '', component: MainPageComponent},
          {path: 'main', redirectTo: ''},
          {path: '**', component: ErrorPageComponent}
        ];
        

        【讨论】:

          猜你喜欢
          • 2013-05-26
          • 1970-01-01
          • 1970-01-01
          • 2014-10-05
          • 1970-01-01
          • 2011-01-14
          • 1970-01-01
          • 2014-12-09
          相关资源
          最近更新 更多