Angular 9 - 为给定的 url 解析每个参数
Angular 9 - parse each parameter for a given url
假设我们有这些 urls:
[1] /home/users/:id
[2] /home/users/:id/posts/:id
[3] /home/users/:id/posts/:id/comments/:id
我想创建一个方法 parseUrl(url: string): any[] {} url 和 returns 包含 url 的每个参数的数组。所以,parseUrl('/home/users/:id/posts/:id/comments/:id')
将导致 [userId, postId, commentId]
我该如何实现?
天真的做法:
假设我们知道哪些 url 段可以包含参数(在这种情况下,users、posts 和 comments), 我们可以将 url 拆分为 '/'
字符,检查该段是否等于 users 或 posts或评论,最后取后续段为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;
}
为什么这很糟糕? --> 它实际上与 url 的结构高度耦合。例如,如果我也有一个像这样的 url:/home/users/new-post
,那么 new-post
将被视为参数。
使用 ActivatedRoute
或 ActivatedRouteSnapshot
: 使用 params 属性 的 *ActivatedRouteSnapshot` 似乎更好,因为它不受我们 url 的结构影响。这里的问题是,在我的特定情况下,我只能检索最后一个 url 段的参数。所以
parseUrl(route: ActivatedRouteSnapshot) {
return route.params;
}
将导致对象仅包含例如 {'id': 5}
将 /home/users/10/posts/10/comments/5
作为当前 url。这是因为(至少我认为)我已经为 users、posts 配置了 lazy loaded 模块和 评论。所以我有 3 个路由模块,一个匹配路由 users/:id
,第二个匹配 posts/:id
,第三个匹配 comments/:id
。我发现 ActivatedRouteSnapshot 将它们视为 3 个单独的 url 段,每个段有一个参数,而不是一个 url 有 3 个参数。
所以最后,有没有一种程序化的通用方法可以从 Anuglar 9 中的 url 获取每个参数?
您可以使用可选参数,而不是使用“必需的”路由参数,让您通过路由发送对象。
尝试以下方法
路径配置
{ path: '/home/users/', component: UsersComponent }
调用路由
<a [routerLink]="['/home/users', { data: JSON.stringify([userId, postId, commentId]) }]">...</a>
或
this.router.navigate(['/home/users', { data: JSON.stringify([userId, postId, commentId]) }]);
结果URL
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
。如果您想保留旧的参数键名称,则需要相应地调整代码段。
它可能看起来像这样:
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);
}
假设我们有这些 urls:
[1] /home/users/:id
[2] /home/users/:id/posts/:id
[3] /home/users/:id/posts/:id/comments/:id
我想创建一个方法 parseUrl(url: string): any[] {} url 和 returns 包含 url 的每个参数的数组。所以,parseUrl('/home/users/:id/posts/:id/comments/:id')
将导致 [userId, postId, commentId]
我该如何实现?
天真的做法:
假设我们知道哪些 url 段可以包含参数(在这种情况下,users、posts 和 comments), 我们可以将 url 拆分为 '/'
字符,检查该段是否等于 users 或 posts或评论,最后取后续段为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;
}
为什么这很糟糕? --> 它实际上与 url 的结构高度耦合。例如,如果我也有一个像这样的 url:/home/users/new-post
,那么 new-post
将被视为参数。
使用 ActivatedRoute
或 ActivatedRouteSnapshot
: 使用 params 属性 的 *ActivatedRouteSnapshot` 似乎更好,因为它不受我们 url 的结构影响。这里的问题是,在我的特定情况下,我只能检索最后一个 url 段的参数。所以
parseUrl(route: ActivatedRouteSnapshot) {
return route.params;
}
将导致对象仅包含例如 {'id': 5}
将 /home/users/10/posts/10/comments/5
作为当前 url。这是因为(至少我认为)我已经为 users、posts 配置了 lazy loaded 模块和 评论。所以我有 3 个路由模块,一个匹配路由 users/:id
,第二个匹配 posts/:id
,第三个匹配 comments/:id
。我发现 ActivatedRouteSnapshot 将它们视为 3 个单独的 url 段,每个段有一个参数,而不是一个 url 有 3 个参数。
所以最后,有没有一种程序化的通用方法可以从 Anuglar 9 中的 url 获取每个参数?
您可以使用可选参数,而不是使用“必需的”路由参数,让您通过路由发送对象。
尝试以下方法
路径配置
{ path: '/home/users/', component: UsersComponent }
调用路由
<a [routerLink]="['/home/users', { data: JSON.stringify([userId, postId, commentId]) }]">...</a>
或
this.router.navigate(['/home/users', { data: JSON.stringify([userId, postId, commentId]) }]);
结果URL
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
。如果您想保留旧的参数键名称,则需要相应地调整代码段。
它可能看起来像这样:
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);
}