【问题标题】:How is routing with nested modules supposed to work in Angular 2?嵌套模块的路由应该如何在 Angular 2 中工作?
【发布时间】:2017-01-30 06:22:55
【问题描述】:

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

在这个应用程序中,我有很多嵌套组件,根据 Google 的文档,这些组件应该组织为模块中的功能。我的应用中的典型 URL 如下所示

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

但也有一些其他的,比如

user/34/settings

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

我已阅读文档,这些文档相当冗长,并不急于切入正题,却发现根本没有涵盖此案例。我不敢相信这种情况是行不通的,这似乎是一个巨大的疏忽,所以我想问题是我还没有完全理解这个路由器是如何工作的——我有一种感觉,我m 不是唯一的。

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

在这个 plunker 中我有 2 层嵌套

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

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

benutzer/78/klient/56

即路由器实际上找到该路由,而目前它没有。

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

klient/56

这是不可能的。似乎在另一个模块中定义的每个路由都被添加到根而不是相互叠加。

非常感谢任何帮助。

【问题讨论】:

    标签: angular angular2-routing angular2-router3


    【解决方案1】:

    看看你所有的路线。

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

    我说这个选项更具侵入性,因为它迫使孩子们了解父母。在 Angular 2 架构中,这与我们构建组件的方式背道而驰。父母应该了解孩子,但不一定相反。

    我能想到的另一个选择是使用loadChildren 懒加载子模块。我说“懒惰”是因为我不知道如何急切地做到这一点,甚至不确定是否有可能这样做。懒惰地加载孩子,我们可以这样做

    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 }
    ];
    

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

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

    IMO,延迟加载看起来更干净,因为孩子不知道父级,但这强制您延迟加载模块,这可能是不希望的。但在某些情况下,这是需要的,因为它允许更轻的初始负载。

    有关延迟加载的更多信息,请参阅Asynchronous Routing 上的文档路由部分

    【讨论】:

    • 确实,有很多文档,而这个真实世界的场景根本没有涉及。实际上,他们暗示了嵌套模块/路由,但他们从未提出示例,所以我的猜测是他们只是在 final 中跳过了这个功能。
    • 标记为答案,因为使用延迟加载的替代解决方案,这是我最终解决的问题。
    • 我也选择了第二个解决方案,但我吓坏了,这么简单的事情还没有实现。
    【解决方案2】:

    找到一个可能的解决方案,从https://stackoverflow.com/a/39629949/370935复制我的答案

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

    理解我的方法的关键是,所有路由,无论在模块中嵌套多深,都被添加到根模块中。简单的例子,假设我们有一个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 就不再积极参与,但您仍然可以从ActivatedRoute 访问每个参数:

    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 团队的下一个重大更改。

    【讨论】:

    • 我只是在测试和写an answer 当你发布你的:-) 我的答案的第一部分提供了一个与你的几乎相同的解决方案,但提供了延迟加载的第二个解决方案。看看吧。
    猜你喜欢
    • 2017-06-11
    • 2019-08-04
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 2021-11-06
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多