角度9-解析给定网址的每个参数

问题描述

假设我们有以下几种网址:

[1] /home/users/:id

[2] /home/users/:id/posts/:id

[3] /home/users/:id/posts/:id/comments/:id

我想创建一个方法 parseUrl(url:string):any [] {} ,该方法接受一个url并返回包含该参数的每个参数的数组网址。因此,parseUrl('/home/users/:id/posts/:id/comments/:id')将导致[userId,postId,commentId]如何实现?

天真的方法 假设我们知道哪些网址段可以包含参数(在这种情况下,是 users posts comments ),我们可以将网址除以{{ 1}}字符,检查该段是否等于 users posts comments ,最后将后续段作为url。>

'/'

为什么这很烂?->实际上,它与网址的结构高度相关。例如,如果我也有这样的网址:parseUrl(url: string): any[] { let params = new Array<any>(); url.split('/') .filter((segment,index,urlSegments) => index > 0 && ['users','posts','comments'].includes(urlSegments[index - 1])) .forEach(segment => params.push(segment)) return params; } ,那么/home/users/new-post将被视为参数。

使用new-postActivatedRoute 使用* ActivatedRouteSnapshot`的 params 属性似乎更好,因为它是免费的根据我们网址的结构。这里的问题是,在我的特定情况下,我只能检索最后一个URL段的参数。所以

ActivatedRouteSnapshot

将导致仅包含parseUrl(route: ActivatedRouteSnapshot) { return route.params; } 的对象给出{'id': 5}作为当前URL。这是因为(至少我认为)我已经为用户帖子评论配置了惰性加载模块。所以我有3个路由模块,一个匹配路由/home/users/10/posts/10/comments/5,第二个匹配users/:id,第三个匹配posts/:id。我发现ActivatedRouteSnapshot将它们视为3个单独的url段,每个段具有一个参数,而不是一个具有3个参数的单个url。

最后,是否有一种编程的通用方法可以从 Anuglar 9 中的网址获取每个参数?

解决方法

您可以使用可选的参数,而不是使用“必需的”路由参数。该参数使您可以通过路由发送对象。

尝试以下

路径配置

{ path: '/home/users/',component: UsersComponent }

呼叫路线

<a [routerLink]="['/home/users',{ data: JSON.stringify([userId,postId,commentId]) }]">...</a>

this.router.navigate(['/home/users',commentId]) }]);

结果网址

http://myapp.com/home/users;data=...

检索数据

JSON.parse(this.router.snapshot.paramMap.get('data'));
,

您将需要递归遍历路由器树以收集所有参数。 仅当您的paramKeys唯一时,此代码段才有效,因此

/home/users/:id/posts/:id/comments/:id必须为/home/users/:userId/posts/:postId/comments/:commentId。如果您想保留旧的paramkey名称,则需要相应地修改代码段。

它可能看起来像这样:

export parseUrl(route: ActivatedRouteSnapshot): Map<string,string> {
  const result = reduceRouterChildrenParams(route.root.firstChild,new Map<string,string>());
  return result;
}

reduceRouterChildrenParams(routerChild: ActivatedRouteSnapshot | null,data: Map<string,string>): RouteWalkerResult {
  if (!routerChild) {
      return data;
  }
  for (const paramMapKey of routerChild.paramMap.keys) {
    data.set(paramMapKey,routerChild.paramMap.get(paramMapKey)!);
  }
  return routerChild.children.reduce((previousValue,currentValue) => {
    return reduceRouterChildrenParams(currentValue,previousValue);
  },data);
}