如何从子路由导航到父路由?

125

我的问题相当经典。我有一个应用程序的私有部分,它在 登录表单 后面。当登录成功后,它会进入到管理应用程序的 子路由

我的问题是,我无法使用 全局导航菜单,因为路由器试图在 AdminComponent 中进行路由而不是在 AppComponent 中进行路由。所以我的导航菜单出现了问题。

另一个问题是,如果有人想直接访问URL,我希望将其重定向到父级的“登录”路由。但我做不到。对我来说,这两个问题看起来很相似。

有什么想法可以解决吗?


4
请添加一些代码 - Jiang YD
正如其他人所指出的那样,请添加一些代码或基本路由配置,以使您的问题能够吸引更精确的答案。 - Junaid
12个回答

204

你想要一个链接/HTML还是想要在代码中进行路由的操作?

链接: RouterLink指令始终将提供的链接视为相对于当前URL的增量:

[routerLink]="['/absolute']"
[routerLink]="['../../parent']"
[routerLink]="['../sibling']"
[routerLink]="['./child']"     // or
[routerLink]="['child']" 

// with route param     ../../parent;abc=xyz
[routerLink]="['../../parent', {abc: 'xyz'}]"
// with query param and fragment   ../../parent?p1=value1&p2=v2#frag
[routerLink]="['../../parent']" [queryParams]="{p1: 'value', p2: 'v2'}" fragment="frag"

使用 RouterLink 时,请记得导入并使用 directives 数组:

import { ROUTER_DIRECTIVES } from '@angular/router';
@Component({
    directives: [ROUTER_DIRECTIVES],

命令式navigate() 方法需要一个起始点(即相对于relativeTo参数)。如果没有提供,则导航是绝对的:

import { Router, ActivatedRoute } from '@angular/router';
...
constructor(private router: Router, private route: ActivatedRoute) {}
...
this.router.navigate(["/absolute/path"]);
this.router.navigate(["../../parent"], {relativeTo: this.route});
this.router.navigate(["../sibling"],   {relativeTo: this.route});
this.router.navigate(["./child"],      {relativeTo: this.route}); // or
this.router.navigate(["child"],        {relativeTo: this.route});

// with route param     ../../parent;abc=xyz
this.router.navigate(["../../parent", {abc: 'xyz'}], {relativeTo: this.route});
// with query param and fragment   ../../parent?p1=value1&p2=v2#frag
this.router.navigate(["../../parent"], {relativeTo: this.route, 
    queryParams: {p1: 'value', p2: 'v2'}, fragment: 'frag'});

// navigate without updating the URL 
this.router.navigate(["../../parent"], {relativeTo: this.route, skipLocationChange: true});

1
router.navigate(string)方法在当前版本的Angular(2.2)中似乎不存在。我在文档中搜索,只找到了navigate(commands: any[], extras?: NavigationExtras) : Promise<boolean>。或者是我完全错过了什么? - Tomato
2
@Tomato,你需要在这些路由周围放上[]。例如:this.router.navigate(["../../parent"], {relativeTo: this.route}); - gye
2
当您在HTML中使用[routerLink]而不是TypeScript时,如何传递'relativeTo'数据? - redfox05
这与服务一样吗? - oCcSking
1
由于某些原因,在我的情况下,我必须使用“../../../”而不是“../”来导航到父级(从“'/users/1'”到“'/users'”)。 - nelson6e65
有一件值得注意的事情是,路由器和activatedRoute需要在组件本身中注入,这不能被包装成额外的服务和像goUp这样的方法。 - Simon Hansen

74

截至2017年春季,这对我似乎有效:

goBack(): void {
  this.router.navigate(['../'], { relativeTo: this.route });
}

在您的组件构造函数中接受 ActivatedRouteRouter 时,导入如下所示: import { ActivatedRoute, Router } from '@angular/router';

7
与其提及日期,更有用的是提及您正在使用的Angular版本。 - isherwood
@isherwood 我同意。抱歉。如果我没记错的话,我是为 Angular 4.0.x 编写的,而且在 4.3.x 中仍然可用。不幸的是,我现在已经离开了 Angular。 - ne1410s
@ne1410s 非常感谢,我漏掉了相对路径:this.route。 - Ian Samz
注意:懒加载模块中不能使用额外的路由器段。例如:parentPath:'work:queue'(具有子级),并且这些子级使用参数加载子模块。fullCurrentPath:'work/shipping/module/list'。以上代码无法从fullCurrentPath加载parentPath - Don Thomas Boyle

51
你可以像这样导航到父级根目录。
this.router.navigate(['.'], { relativeTo: this.activeRoute.parent });

您需要在构造函数中注入当前活动的路由。

constructor(
    private router: Router,
    private activeRoute: ActivatedRoute) {

  }

2
添加一些解释会使这个答案更有用。 - Sagar Zala
1
许多人建议使用以下代码导航到兄弟组件:this.router.navigate(["../sibling"], {relativeTo: this.route});然而,这种方法已经不再起作用了。我发现以下答案可以正常工作。将相对路径从this.route更改为this.route.parent,而不是使用'../'来导航到父级组件,这才是正确的方式。 - Terry Lam
1
@ChrisLamothe:哦,是的,我犯了一个错误。它在一般情况下是有效的。但是,在辅助路由中它不起作用。这意味着this.router.navigate(['../sibling'])可以工作,但是this.router.navigate([{outlets: {'secondary': ['../sibling']}}])不能工作。在辅助路由中,我必须使用this.router.navigate([{outlets: {'secondary': ['sibling']}}], {relativeTo:this.activatedRoute.parent}). - Terry Lam
2
此外,从这个答案中的导航方法 this.router.navigate(['.'], {relativeTo: this.activeRoute.parent}); 在以下情况下可以正确工作:当您在两个路径中使用相同的组件时:/users/create 和 /users/edit/123。在这两种情况下,它都会导航到父级 /users。常规导航 this.router.navigate([".."], {relativeTo: this.activeRoute}) 只适用于 users/create,但对于 users/edit/123 将不起作用,因为它将导航到不存在的 /users/edit/ 路由。 - Roganik
2
+1 是一个备选方案,但我有点喜欢追逐字节,并会在参数中投资一个额外的点“*[".."]”,以消除对父级的引用,{ relativeTo: this.route }*。 - Konrad Viltersten
显示剩余2条评论

12

不多说了:

this.router.navigate(['..'], {relativeTo: this.activeRoute, skipLocationChange: true});

参数'..'可以使得导航上一级,即父级 :)


1
你可能需要提到 skipLocationChange 的目的/需求。 - Konrad Viltersten
2
除了之前的评论外,还要添加一个参考,说明“this.activeRoute”与什么相关。 - Cafn

9
constructor(private router: Router) {}

navigateOnParent() {
  this.router.navigate(['../some-path-on-parent']);
}

该路由器支持以下路径:

  • 绝对路径 /xxx - 以根组件的路由器为起点
  • 相对路径 xxx - 以当前组件的路由器为起点
  • 相对路径 ../xxx - 以当前组件的父级路由器为起点

尽管这段代码可能回答了问题,但提供关于它为什么和/或如何回答问题的额外上下文会显著提高其长期价值。请编辑您的答案以添加一些说明。 - Toby Speight
1
@TobySpeight 好的,我理解了。我以为 ../ 已经足够熟悉了,但最终还是有歧义的。感谢你的提示。 - Günter Zöchbauer
1
谢谢你的回答,我已经在这个网站上工作了相当长的时间,所以Angular显然已经更新了。我已经尝试在我的当前版本中使用这个解决方案,但它不起作用。让我更新一下,之后再回复评论。 - Carl Boisvert
1
我无法让你的代码按预期工作。但是,通过在调用* navigate 时将明确的,{relativeTo:this.route} *作为第二个参数添加,它可以工作。如果不是因为你的答案通常具有极高的准确度,我会把它归咎于愚蠢的打字错误。也许自回答提供以来(3.6年前,在Angular年代中就像半个“永恒”),路由器的行为发生了变化? - Konrad Viltersten
这是一个旧答案,路由器在此期间发生了很大变化。考虑到有几个得票更高的答案,我认为我的答案已经过时了。我现在不再做太多的Web UI工作,也没有所有细节记在脑海中。 - Günter Zöchbauer

6

无论当前路由或父级路由中有多少个参数,都可以导航到父级组件Angular 6更新于1/21/19

   let routerLink = this._aRoute.parent.snapshot.pathFromRoot
        .map((s) => s.url)
        .reduce((a, e) => {
            //Do NOT add last path!
            if (a.length + e.length !== this._aRoute.parent.snapshot.pathFromRoot.length) {
                return a.concat(e);
            }
            return a;
        })
        .map((s) => s.path);
    this._router.navigate(routerLink);

这样做还有一个附加好处,就是您可以使用单例路由器的绝对路径。(适用于Angular 4+,很可能也适用于Angular 2。)

奇怪的是,这总是返回一个空数组,并且与this._router.navigate([])达到相同的结果,而this._router.navigate([[]])只有在父路由不是根路由本身时才会带到父路由。 - DesTroy
更新了代码以反映Angular 6的更改,并在路由中正确查找父级和包含子级的父级和子级。 - Don Thomas Boyle
你确定这不是你的用例特定的问题吗?似乎不附加最后一个路径将会把 ['orders', '123', 'items', 1] 转换为只有 ['orders'],这看起来完全不正确。无论如何,我们刚刚从 Angular 5 升级到了 7,并没有触及这段代码。 - kayjtea
我的页面上有许多div。每次点击一个div时,我都会传递查询参数并加载一个组件。现在我想使用浏览器的后退按钮返回,该怎么做? - Vrajendra Singh Mandloi

6

另一种方式可以像这样

this._router.navigateByUrl(this._router.url.substr(0, this._router.url.lastIndexOf('/'))); // go to parent URL

这是构造函数的部分代码

constructor(
    private _activatedRoute: ActivatedRoute,
    private _router: Router
  ) { }

2

每个人都建议使用相对路径,但真正忘记了最重要的部分:相对路径始终取决于您路由中可能存在的参数。

例如,如果您有一个子路由edit/:id,并且您的id是格式化为/api/something/123的URI,则为了使用相对路由到达父级,您需要使用[../../../..']。 换句话说,将URL视为计算机上的目录结构。不要根据路由表中创建的定义来考虑路由。


2

我的路由模式如下:

  • user/edit/1 -> 编辑
  • user/create/0 -> 创建
  • user/ -> 列表

例如,当我在编辑页面时,需要返回到列表页面,我将在路由中返回两个级别。

考虑到这一点,我创建了一个带有“级别”参数的方法。

goBack(level: number = 1) {
    let commands = '../';
    this.router.navigate([commands.repeat(level)], { relativeTo: this.route });
}

所以,要从编辑转到列表,我这样调用方法:
this.goBack(2);

1

对我来说这些都没有用......这是我的代码,带有后退功能:

import { Router } from '@angular/router';
...
constructor(private router: Router) {}
...
back() {
   this.router.navigate([this.router.url.substring(0, this.router.url.lastIndexOf('/'))]);
}

this.router.url.substring(0, this.router.url.lastIndexOf('/') --> 获取当前 url 中最后一个 "/" 后面的部分 --> 获取当前路由。


请在您的答案中更新一些描述为什么这个方法有效。请参阅如何回答 - Gerald Zehetner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接