Angular 2 应该如何使用嵌套模块进行路由?

How is routing with nested modules supposed to work in Angular 2?

出于对 cookie 的热爱,我无法弄清楚如何配置 Angular 2 路由器的最新版本(最终版本中的那个)。我有一个相当大的 Angular 2 RC5 应用程序和 运行,但现在需要迁移到最终版本才能继续。

在这个应用程序中,我有很多嵌套组件,根据 Google 的文档,这些组件应该组织为模块中的功能。我的应用程序中典型的 URL 看起来像这样

user/34/section/95/client/13/<feature>

但也有一些其他的,比如

user/34/settings

所以在这种情况下,settings 将是一个功能模块。

我看了文档,比较啰嗦,不急着开门见山,才发现根本没有涉及到这个案例。我不敢相信这种情况不会奏效,这似乎是一个巨大的疏忽,所以我想问题是我还没有完全理解这个路由器的实际工作原理——我有一种感觉我不止一个

我创建了 this plunker 来说明我的观点。

在这个 plunker 中我有 2 层嵌套

app -> benutzer (user) -> klient (client)

足以使问题出现。预期的结果是我可以导航到

benutzer/78/klient/56

即路由器实际上找到了那条路线,但目前还没有。

在我将代码移动到plunker并添加dashboard.component之前(因为我不能轻易修改plunker中的URL,所以我不得不求助于routerLink)我可以实际上导航到

klient/56

这是不可能的。似乎在另一个模块中定义的每个路由都被添加到根而不是在彼此之上构建。

非常感谢任何帮助。

找到了一个可能的解决方案,复制了我在

中的答案

我也让这个工作正常,除非你真的需要渲染层次结构中的所有父组件,否则我认为我的解决方案要优雅得多。

理解我的方法的关键是所有路由,无论嵌套在模块中有多深,都被添加到根模块中。快速示例,假设我们有一个 DepartmentModule 和一个 EmployeeModule,我们想使用此 URL

导航到它们
/department/1/employee/2

此时我们将看到员工 2 的详细信息。为 department.routing.ts 中的 departmentemployee.routing.ts 中的 employee 配置路由将 不会 按我们预期的方式工作,您会注意到可以导航到

/employee/2

从根组件开始,而

/department/1/employee/2

会崩溃(找不到路线)。这种情况下的典型路由配置如下所示:

export const departmentRoutes: Routes = [
    { path: 'department', component: DepartmentComponent, children: [
        { path: '', component: DepartmentsComponent },
        { path: ':id', component: DepartmentDetailsComponent }
    ]}
];

export const employeeRoutes: Routes = [
    { path: 'employee', component: EmployeeComponent, children: [
        { path: '', component: EmployeesComponent },
        { path: ':id', component: EmployeeDetailsComponent }
    ]}
];

EmployeeModule 将由 DepartmentModule 导入。现在,就像我说的,不幸的是,这不起作用。

但是,只需进行一次更改,它将:

export const employeeRoutes: Routes = [
    { path: 'department/:id/employee', component: EmployeeComponent, children: [
        { path: '', component: EmployeesComponent },
        { path: ':id', component: EmployeeDetailsComponent }
    ]}
];

要注意的是,当您导航到 employee URL 时,DepartmentModule 不再积极参与,但您仍然可以访问 [=] 中的每个参数26=]:

export class EmployeeDetailsComponent {
    departmentId: number;
    employeeId: number;
    constructor(route: ActivatedRoute) {
        route.parent.params.subscribe(params =>
            this.departmentId= +params['id'])
        route.params.subscribe(params => 
            this.employeeId= +params['id']);
    }
}

我想知道这是否应该是官方方法,但目前这对我有用,直到 Angular 2 团队的下一个突破性更改。

查看所有路线。

appRoutes = [      // AppModule
  { path: '', redirectTo: 'dashaboard' },
  { path: 'dashboard', component: DashboardComponent
];
benutzerRoutes = [ // BenutzerModule
  { path: 'benutzer/:id', component BenutzerComponent }
];
klientRoutes = [   // KlinetModule
  { path: 'klient/:id', component: KlientComponent }
]

导入模块的方式对路由的构建方式没有任何影响。它们的构建方式完全基于我们构建的方式。您对此有何期待

AppModule
   imports -> BenutzerModule
                   imports -> KlinetModule

通往以下路线

dashboard/benutzer/:id/klient/:id

事实并非如此。这些路由数组中的每一个都被简单地添加到根。这就是为什么您可以访问 klient/:id 而不是 dashboard/benutzer/:id.

我已经阅读了几次完整的路由文档,但在不同的模块中没有任何嵌套路由的示例。所有示例都有从根路由加载的模块,就像您的示例一样,或者嵌套路由是同一路由配置的一部分。因此,由于没有示例,我想我们只需要使用我们所知道的并自行决定什么是最好的方法。

我可以想到几种方法。第一个,也是最明显的,但 IMO 比下一个选项更具侵入性,就是将完整的路由添加到路径

appRoutes = [      // AppModule
  { path: '', redirectTo: 'dashaboard' },
  { path: 'dashboard', component: DashboardComponent
];
benutzerRoutes = [ // BenutzerModule
  { path: 'dashboard/benutzer/:id', component BenutzerComponent }
];
klientRoutes = [   // KlinetModule
  { path: 'dashboard/benutzer/:id/klient/:id', component: KlientComponent }
]

我说这个选项更具侵入性,因为它迫使 children 知道 parent。在 Angular 2 架构中,这与我们构建组件的方式背道而驰。 Parents应该知道child仁,反之则不一定。

我能想到的另一个选择是使用 loadChildren 延迟加载 child 模块。我说 "lazily" 是因为我无法弄清楚如何急切地做到这一点,并且不确定是否有可能这样做。要延迟加载 children,我们可以这样做

export const appRoutes: Routes = [
  { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
  { path: 'dashboard', component: DashboardComponent },
  {
    path: 'dashboard/benutzer',
    loadChildren: 'app/benutzer/benutzer.module#BenutzerModule'
  },
  { path: '**', component: NotFoundComponent }
];
export const benutzerRoutes: Routes = [
  { path: ':id', component: BenutzerComponent },
  {
    path: ':id/klient',
    loadChildren: 'app/klienten/klienten.module#KlientenModule'
  }
];
export const klientenRoutes: Routes = [
  { path: ':id', component: KlientComponent }
];

在这种情况下,我们将从 parent @NgModule 中删除所有 child 模块导入。这允许延迟加载模块。如果我们离开,那么模块将在启动时急切加载,但没有达到预期的效果(因此我说我不是如何急切地这样做)。

另请注意 loadChildren。在上面的示例中,我使用 app 作为根。唯一的原因是我在本地环境中进行了测试。我不是 Plunker 的忠实粉丝。不过,对于您的 Plunker,您应该使用 src 作为根。

IMO,延迟加载 看起来 更干净,因为 child 不知道 parent,但这 forces 你延迟加载模块,这可能不是你想要的。但在某些情况下,这是需要的,因为它允许更轻的初始负载。

有关延迟加载的更多信息,请参阅 Asynchronous Routing

上的文档路由部分