Angular 中的嵌套路由

Abr*_*ain 5 angular-routing angular angular-router

这可能是一个常见问题,如果有更好的答案,请指点我。话虽如此,问题来了:

在顶层,我正在开发的 angular 应用程序公开了一个登录路径和 4 个独立仪表板的路径,具体取决于谁登录。这部分按预期工作。

对于每个仪表板,我都有一个大致相同的侧面导航(某些选项仅针对某些类型的用户显示)。在仪表板中,我有一个嵌套的路由器插座。每当我尝试在嵌套插座内加载模块时,Angular 都无法匹配路径。这是我到目前为止所拥有的:

app-routing.module.ts

const routes: Routes = [
  { path: '', pathMatch: 'full', redirectTo: 'login' },
  { path: 'login', loadChildren: () => import('./modules/auth/auth.module').then(m => m.AuthModule) },
  //{ path: 'dashboard', loadChildren: () => import('./modules/dashboard/dashboard.module').then(m => m.DashboardModule) }
  { path: 'admin', loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule) },
];
Run Code Online (Sandbox Code Playgroud)

admin-routing.module.ts


const routes: Routes = [
  { path: '', pathMatch: 'full', component: AdminComponent, children: [
    { path: 'employee', loadChildren: () => import('./../employee/employee.module').then(m => m.EmployeeModule) },
    { path: 'attendance', loadChildren: () => import('./../attendance/attendance.module').then(m => m.AttendanceModule) },
    { path: 'customer', loadChildren: () => import('./../customer/customer.module').then(m => m.CustomerModule) },
    { path: 'order', loadChildren: () => import('./../order/order.module').then(m => m.OrderModule) },
    { path: 'expense', loadChildren: () => import('./../expense/expense.module').then(m => m.ExpenseModule) },
  ]},
];
Run Code Online (Sandbox Code Playgroud)

应用程序组件.html

<router-outlet></router-outlet>
Run Code Online (Sandbox Code Playgroud)

管理组件.html

<mat-drawer-container mode="side" id="dashboard-drawer-container" hasBackdrop="false">
  <mat-drawer #drawer id="sidenav-container">
    <app-sidenav></app-sidenav>
  </mat-drawer>
  <div id="dashboard-container">
    <router-outlet></router-outlet>
  </div>
</mat-drawer-container>
Run Code Online (Sandbox Code Playgroud)

现在预期的行为如下:

  1. 当导航到 /admin 时,将呈现 AdminComponent 并且 sidenav 将可见
  2. 当在 sidenav 点击链接时,内容应该在 admin 组件中的嵌套路由器中呈现(例如,admin/employee)
  3. 当在 (2) 中加载的模块内部访问其他路由时,它应该在该模块中的出口内呈现(例如,admin/employee/:id)用于员工详细信息页面,其中员工模块具有嵌套路由器

我尝试使用命名插座,但它不断抛出错误。如果我将孩子从管理路由中移出并使它们成为独立路由,它会起作用,但是,内容会呈现在最外面的(应用程序)路由器出口上,并且不会呈现 sidenav。

任何帮助或建议将不胜感激。

And*_*tej 6

让我们把问题分解成一个小问题:

app.module.ts

const routes: Routes = [
  {
    path: '',
    // pathMatch: 'full',
    children: [
      {
        path: 'foo',
        component: FooComponent
      },
    ],
  },
  {
    path: '**',
    component: NotFoundComponent,
  }
];
Run Code Online (Sandbox Code Playgroud)

应用程序组件.html

<router-outlet></router-outlet>

<button routerLink="/foo">go to foo</button>
Run Code Online (Sandbox Code Playgroud)

运行演示


如果我们点击按钮,Angular Router 将安排一个路由转换。这涉及到一个非常有趣的过程,它由多个阶段组成。

这些阶段之一是称为应用重定向的阶段,它是解决重定向的地方,也是NoMatch错误的来源。这也是我们可以找到更多关于pathMatch: 'full'.
在这个阶段,它将遍历每个配置对象,并尝试找到与发布的 url 匹配的第一个对象(例如/foo)。

它将首先遇到这个(它发生在matchSegmentAgainstRoute):

{
  path: '',
  // pathMatch: 'full',
  children: [
    {
      path: 'foo',
      component: FooComponent
    },
  ],
},
Run Code Online (Sandbox Code Playgroud)

然后,该match函数将被调用:

const {matched, consumedSegments, lastChild} = match(rawSegmentGroup, route, segments);
Run Code Online (Sandbox Code Playgroud)

在这里,我们停在route.path === ''

if (route.path === '') {
  if ((route.pathMatch === 'full') && (segmentGroup.hasChildren() || segments.length > 0)) {
    return {matched: false, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
  }

  return {matched: true, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
}
Run Code Online (Sandbox Code Playgroud)

因此,这是一种pathMatch选择产生差异的情况。使用当前配置(pathMatch未设置),

return {matched: true, consumedSegments: [], lastChild: 0, positionalParamSegments: {}};
Run Code Online (Sandbox Code Playgroud)

将到达,然后它将继续通过children阵列。因此,在这种情况下,FooComponent将成功显示。

但是,如果我们有pathMatch: 'full',那么表达式

if ((route.pathMatch === 'full') && (segmentGroup.hasChildren() || segments.length > 0)) { }
Run Code Online (Sandbox Code Playgroud)

将是true,因为segments.length > 0在这种情况下段是['foo']。所以,我们会得到matched: false,这意味着FooComponent不会出现在视图中。