代码之家  ›  专栏  ›  技术社区  ›  Dinaiscoding

在命名出口中传递参数无效

  •  0
  • Dinaiscoding  · 技术社区  · 5 年前

    伙计们,我一直很难让这段代码正常工作。

    基本上,我希望将一些参数传递给嵌套的和命名的 router-outlet .

    回购协议: https://stackblitz.com/edit/angular-hsezw8-rp5ne9?file=src/app/crisis-center/crisis-list/crisis-list.component.html

    我正在使用下面的 routerLink :

        <a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
          <span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
        </a>
    ...
    <router-outlet name="test"></router-outlet>
    

    我的路线如下:

    {
            path: '',
            component: CrisisListComponent,
            children: [
              {
                path: ':id',
                component: CrisisDetailComponent,
                canDeactivate: [CanDeactivateGuard],
                resolve: {
                  crisis: CrisisDetailResolverService
                },
                outlet: 'test'
              },
              {
                path: '',
                component: CrisisCenterHomeComponent
              }
            ]
          }
    

    在stackoverflow中搜索后,根据答案,这应该是有效的,但不是。有人知道我错过了什么吗? 提前谢谢

    0 回复  |  直到 5 年前
        1
  •  1
  •   Andrei Gătej    5 年前

    编辑

    我写了一篇文章,详细介绍了Angular 11附带的新修复: Angular Router: empty paths, named outlets and a fix that came with Angular 11 .


    太长,读不下去了

    Working demo.


    详细说明

    为什么它一开始不起作用

    A. TLRD 因为,具有(嵌套)空路径的命名出口并不总是 打得好 (至少在旧版本中)。这就是其中之一。

    首先,重要的是要提到Angular Router如何处理路由及其变化。例如,它通过一个名为 UrlTree 1. .UrlTree可被视为 反序列化版本 URL的名称,它是一个字符串。给予 UrlTree ,路由配置数组将基于此路径遍历(以DFS方式) UrlTree . UrlTree的根是另一个结构, UrlSegmentGroup :

    constructor(
      /** The URL segments of this group. See `UrlSegment` for more information */
      public segments: UrlSegment[],
      /** The list of children of this group */
      public children: {[key: string]: UrlSegmentGroup}) {
    forEach(children, (v: any, k: any) => v.parent = this);
    

    如您所见,它类似于一个规则的树结构。从中选择一段 segments 数组包含 path (例如 'crisis-center' )以及给定路径的矩阵参数。至于 children 属性,其键是 门店名称 (例如 'test' )这些值是 UrlSegmentGroup 实例。通过使用这些结构,Angular Router可以表示URL字符串,并且可以提供许多特性和定制。

    给定来自的路由配置 crisis-center-routing.module.ts :

    const crisisCenterRoutes: Routes = [
      {
        path: '', // (1)
        component: CrisisCenterComponent,
        children: [
          {
            path: '', // (2)
            component: CrisisListComponent,
            children: [
              {
                path: ':id', // (3)
                component: CrisisDetailComponent,
                canDeactivate: [CanDeactivateGuard],
                resolve: {
                  crisis: CrisisDetailResolverService
                },
                outlet: 'test'
              },
              {
                path: '',
                component: CrisisCenterHomeComponent
              }
            ]
          }
        ]
      }
    ];
    

    UrlTree 将路由配置对象与 path: ':id' 看起来是这样的:

    // Note: For simplicity, I've only used the `path` to represent the `segments` property
    UrlTree {
      // UrlSegmentGroup
      root: {
        children: {
          primary: {
            children: {
              primary: {
                children: {
                  test: {
                    children: {}
                    segments: [1], // Matches (3)
                  }
                },
                segments: [''], // Matches (1) and (2)
              }
            }
            segments: ['crisis-center'],
          }
        }
        segments: [],
      }
    }
    

    注意:插座的默认名称为 'primary' .

    上述UrlTree可通过以下方式实现:

    <a [routerLink]="['/crisis-center', { outlets: { primary: ['', { outlets: { test: [crisis.id] } }] } }]">
      <span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
    </a>
    

    虽然上述方法在理论上应该有效,但事实并非如此。这是因为 '' 不是 消耗 当这种情况发生时 primary 将选择出口。更具体地说 '' 从…起 primary: ['' ... 将与 (1) ,但第二个 '' (来自 (2) )不会被吃掉的。 然而,这似乎 to be fixed in Angular v12 :

    // At this point, not all paths of the `segment` array have been consumed.
    // This time, the route's outlet is taken into account.
    const matchedOnOutlet = getOutlet(route) === outlet;
    const expanded$ = this.expandSegment(
        childModule, segmentGroup, childConfig, slicedSegments,
        matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
    

    但是 this 过去是这样的:

    // At this point, not all paths of the `segment` array have been consumed.
    // As you can see, it always chooses the `primary` outlet
    const expanded$ = this.expandSegment(
        childModule, segmentGroup, childConfig, slicedSegments, PRIMARY_OUTLET, true);
    

    由于您是旧版本,我们需要找到另一种方法。

    当前的方法也会发生类似的情况:

    <a [routerLink]="[{ outlets: { test: [ crisis.id] } }]">
      <span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
    </a>
    

    但这一次导航将不会成功,因为插座之间会出现不匹配。它最终会失败 (2) ,路线的出口在哪里 主要的,重要的 ,但电源插座根据电流 UrlSegmentGroup 那一刻是 test .

    解决办法

    首先,我注意到 CrisisCenterComponent 没什么作用:

    <h2>CRISIS CENTER</h2>
    <router-outlet></router-outlet>
    

    所以,我们要把它处理掉。这就是我们将得到的:

    危机中心路线。单元ts :

    const crisisCenterRoutes: Routes = [
      {
        // path: '',
        // component: CrisisCenterComponent,
        // children: [
        //   {
            path: '',
            component: CrisisListComponent,
            children: [
              {
                path: ':id',
                component: CrisisDetailComponent,
                canDeactivate: [CanDeactivateGuard],
                resolve: {
                  crisis: CrisisDetailResolverService
                },
                outlet: 'test'
              },
              {
                path: '',
                component: CrisisCenterHomeComponent
              }
            ]
          }
      //   ]
      // }
    ]
    

    现在,自从 CrisisListComponent 作为容器,我们可以进行以下更换:

    危机中心路线。单元ts :

    const crisisCenterRoutes: Routes = [
      {
        // path: '',
        // component: CrisisCenterComponent,
        // children: [
        //   {
            // path: '',
            // component: CrisisListComponent,
            // children: [
            //   {
                path: ':id',
                component: CrisisDetailComponent,
                canDeactivate: [CanDeactivateGuard],
                resolve: {
                  crisis: CrisisDetailResolverService
                },
                outlet: 'test'
              },
              {
                path: '',
                component: CrisisCenterHomeComponent
              }
          //   ]
          // }
      //   ]
      // }
    ]
    

    应用程序路由。单元ts

      {
        path: 'crisis-center',
        loadChildren: () =>
          import('./crisis-center/crisis-center.module').then(
            mod => mod.CrisisCenterModule
          ),
        data: { preload: true },
        // !
        component: CrisisListComponent
      },
    

    所以,不会有额外的 '' (正如我们所见,这有时会导致问题)匹配。

    routerLink 在视图中,将保持不变:

    <[routerLink]=“[{outlets:{test:[crisis.id]}}]”>
    <span class=“徽章”>{{crisis.id}</span>{{crisis.name}
    </a>
    

    作为旁注,现在当您选择一个危机中心时 CrisisCenterHomeComponent 也将是活跃的。如果要避免这种情况,可以执行以下操作:

    危机中心路线。单元ts :

    /* ... */
      {
        path: ':id'
        component: CrisisDetailComponent,
        canDeactivate: [CanDeactivateGuard],
        resolve: {
          crisis: CrisisDetailResolverService
        },
        outlet: 'test'
      },
      {
        path: '',
        // Uncomment this if you want these 2 Route objects
        // to be mutually exclusive(either one of them, not both at the same time)
        pathMatch: 'full',
        component: CrisisCenterHomeComponent
      }
    /* ... */
    

    1: Angular Router: Getting to know UrlTree, ActivatedRouteSnapshot and ActivatedRoute

    如果您想了解更多有关Angular Router及其内部工作/功能的信息,我建议您:

    推荐文章