ChatGPT解决这个技术问题 Extra ChatGPT

如何返回上一页

有没有一种聪明的方法可以返回 Angular 2 的最后一页?

就像是

this._router.navigate(LASTPAGE);

例如,页面 C 有一个返回按钮,

页面 A -> 页面 C,点击它,返回页面 A。

页面 B -> 页面 C,点击它,返回页面 B。

路由器有这个历史信息吗?


K
Kishan Vaishnav

实际上,您可以利用具有“返回”API 的内置位置服务。

这里(在 TypeScript 中):

import {Component} from '@angular/core';
import {Location} from '@angular/common';

@Component({
  // component's declarations here
})
class SomeComponent {

  constructor(private _location: Location) 
  {}

  backClicked() {
    this._location.back();
  }
}

编辑:正如@charith.arumapperuma 所述,Location 应该从 @angular/common 导入,因此 import {Location} from '@angular/common'; 行很重要。


在 Angular 2 的旧版本中,位置应该从“angular2/router”导入。在较新的版本中,它应该来自“@angular/common”。
如果您将它内置在框架中,我认为没有任何理由使用“本机”“window.history.back();”这是一项 HTML5 功能 (developer.mozilla.org/en-US/docs/Web/API/Window/history)
对于它的价值,Location 的官方 Angular2 API 文档指出:“注意:最好使用路由器服务来触发路由更改。仅当您需要与路由交互或创建路由之外的规范化 URL 时才使用位置。” @Sasxa's answer 显然显示了一种使用 Router 来执行此操作的方法。但是,Location 方法肯定更方便。有谁知道为什么 Router 方法可能比 Location 方法更正确?
@Andrew:我遇到了问题,如果你使用 this.location.back(),你不能返回两次。您将跳回初始站点。
@yt61,不确定,也许可重用性?或者如果您可以从各种路线到达指定页面,那么您事先不知道要返回的路线。
D
Daniel Gray

在 Angular 2.x / 4.x 的最终版本中 - 这是文档https://angular.io/api/common/Location

/* typescript */

import { Location } from '@angular/common';
// import stuff here

@Component({
// declare component here
})
export class MyComponent {

  // inject location into component constructor
  constructor(private location: Location) { }

  cancel() {
    this.location.back(); // <-- go back to previous location on cancel
  }
}

在导航回上一个屏幕时,我们可以在不使用服务对象的情况下保留输入的输入值。
如何在 location.back() 执行时显示动画?
N
Nikita Fedyashev

您可以将其放入指令中,该指令可以附加到任何可点击元素:

import { Directive, HostListener } from '@angular/core';
import { Location } from '@angular/common';

@Directive({
    selector: '[backButton]'
})
export class BackButtonDirective {
    constructor(private location: Location) { }

    @HostListener('click')
    onClick() {
        this.location.back();
    }
}

用法:

<button backButton>BACK</button>

棒极了!
如果您在此页面上刷新,并单击触发“this.location.back()”的按钮,它只会触发页面刷新。 Location 模块有什么方法可以检测到以前的路径是否存在?
请记住,如果用户直接转到存在“后退”按钮的页面,并且如果他点击了一个按钮……那么根据浏览器(平台)历史记录,他将被从应用程序中抛出到上一页。
对于未来的读者,请查看 API docs
很棒的解决方案谢谢。
J
JavierFuentes

使用 Angular 5.2.9 测试

如果您使用锚点而不是按钮,则必须使用 href="javascript:void(0)" 将其设为被动链接,以使 Angular Location 工作。

app.component.ts

import { Component } from '@angular/core';
import { Location } from '@angular/common';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent {

  constructor( private location: Location ) { 
  }

  goBack() {
    // window.history.back();
    this.location.back();

    console.log( 'goBack()...' );
  }
}

app.component.html

<!-- anchor must be a passive link -->
<a href="javascript:void(0)" (click)="goBack()">
  <-Back
</a>

我建议创建一个“clickPreventDefault”指令而不是使用 javascript:void(0)。像... @Directive({ selector: '[clickPreventDefault]' }) export class ClickPreventDefaultDirective { @HostListener("click", ["$event"]) onClick($event: Event) { $event.preventDefault(); } }
谢谢@bmd,这是一种更复杂的方式,但它也有效。另一个可行的解决方案是不要使用 herf: 尽管这种方式不通过 HTML Validators。
B
Bhargav Rao

您可以在路由类上实现 routerOnActivate() 方法,它将提供有关先前路由的信息。

routerOnActivate(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction) : any

然后您可以使用 router.navigateByUrl() 并传递从 ComponentInstruction 生成的数据。例如:

this._router.navigateByUrl(prevInstruction.urlPath);

这对 Angular 2.1.0 仍然有效吗?
@smartmouse 我不这么认为,有 routerOnActivate 的文档
此答案中的 routerOnActivate() 链接已损坏。似乎这不是在发布版本中执行此操作的方法。
A
Anjil Dhamala

在所有这些很棒的答案之后,我希望我的答案能找到某人并帮助他们。我写了一个小服务来跟踪路线历史。就这样吧。

import { Injectable } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { filter } from 'rxjs/operators';

@Injectable()
export class RouteInterceptorService {
  private _previousUrl: string;
  private _currentUrl: string;
  private _routeHistory: string[];

  constructor(router: Router) {
    this._routeHistory = [];
    router.events
      .pipe(filter(event => event instanceof NavigationEnd))
      .subscribe((event: NavigationEnd) => {
        this._setURLs(event);
      });
  }

  private _setURLs(event: NavigationEnd): void {
    const tempUrl = this._currentUrl;
    this._previousUrl = tempUrl;
    this._currentUrl = event.urlAfterRedirects;
    this._routeHistory.push(event.urlAfterRedirects);
  }

  get previousUrl(): string {
    return this._previousUrl;
  }

  get currentUrl(): string {
    return this._currentUrl;
  }

  get routeHistory(): string[] {
    return this._routeHistory;
  }
}

在尝试了或多或少的所有解决方案后,我发现这是更一致的方法
如果我打开特定链接上的页面并且我希望它返回到页面树中的页面怎么办?
我在调用 preiousUrl() 时收到错误类型字符串没有调用签名。你能帮我吗? :D
@SzokeLori 听起来您的“this”指向字符串类型。您应该使用代码发布问题。
@AnjilDhamala 好吧...我只是将这个东西作为构造函数的私有注入,并想通过控制台记录它。请注意,我是初学者
S
Shevtsiv Andriy

当我需要像在文件系统中一样移回时,也可以为我工作。 PS @angular: "^5.0.0"

<button type="button" class="btn btn-primary" routerLink="../">Back</button>

我希望这会起作用,但这会回到它上面的下一条路线 - 而不是在导航到页面之前你所在的路线。很高兴知道这存在,但是如果您的组件有多个入口点,则此方法只会返回到它上面的路线,而不是您的来源。
正如我写的“当我需要像在文件系统中一样移回时”:) 对我来说,这种行为也是出乎意料的。
您将 back(例如 cd -)与 up (cd ..) 混淆了。尽管如此,知道这是有效的还是很方便的。
这将返回到父视图(它并不总是等同于前一个视图)
T
Todd Skelton

我做了一个按钮,我可以在我的应用程序的任何地方重复使用。

创建这个组件

import { Location } from '@angular/common';
import { Component, Input } from '@angular/core';

@Component({
    selector: 'back-button',
    template: `<button mat-button (click)="goBack()" [color]="color">Back</button>`,
})
export class BackButtonComponent {
    @Input()color: string;

  constructor(private location: Location) { }

  goBack() {
    this.location.back();
  }
}

然后在需要后退按钮时将其添加到任何模板中。

<back-button color="primary"></back-button>

注意:这是使用 Angular 材质,如果您不使用该库,请移除 mat-buttoncolor


这种方法是否适用于命名路由器插座?假设我在页面上有几个,只想返回其中一个,这行得通吗?
对于这种情况,您必须使用不同的方法。如果您在两个不同的路由器插座中有相同的后退按钮,它们可能都会做同样的事情并返回上一个更改的路由器插座。
对于命名的网点,我发现这种方法有效:this.router.navigate(['../'], {relativeTo: this.route})
如何在另一个组件中使用这个组件?
P
Parziphal

也许您想检查上一个历史点是否在您的应用程序中。例如,如果您直接进入您的应用程序并执行 location.back()(例如,通过按工具栏中的 <- back 按钮),您将返回浏览器的主页,而不是去其他地方 你的应用。

这就是我检查的方式:

import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Location } from '@angular/common';

@Component({
  selector: 'app-foo',
  template: ''
})
export class FooComponent {

  private readonly canGoBack: boolean;

  constructor(
    private readonly route: ActivatedRoute,
    private readonly router: Router,
    private readonly location: Location
  ) {
    // This is where the check is done. Make sure to do this
    // here in the constructor, otherwise `getCurrentNavigation()`
    // will return null. 
    this.canGoBack = !!(this.router.getCurrentNavigation()?.previousNavigation);
  }

  goBack(): void {
    if (this.canGoBack) {
      // We can safely go back to the previous location as
      // we know it's within our app.
      this.location.back();
    } else {
      // There's no previous navigation.
      // Here we decide where to go. For example, let's say the
      // upper level is the index page, so we go up one level.
      this.router.navigate(['..'], {relativeTo: this.route});
    }
  }

}

我们检查加载当前路线的导航是否有前一个兄弟。这必须在构造函数中完成,而导航过程仍处于活动状态。

不过,这并非没有警告:

即使先前的位置实际上在我们的应用程序中但页面已刷新,canGoBack 也会为 false。

用户可能希望通过单击浏览器的后退按钮“返回”到上一页(发生 goBack() 的位置),但由于应用程序返回历史记录而不是推送新位置,用户甚至会返回进一步,可能会感到困惑。


P
Puneeth Rai

我在导航到不同页面时执行此操作的方式通过传递当前位置添加查询参数

this.router.navigate(["user/edit"], { queryParams: { returnUrl: this.router.url }

在您的组件中阅读此查询参数

this.router.queryParams.subscribe((params) => {
    this.returnUrl = params.returnUrl;
});

如果 returnUrl 存在,则启用后退按钮,并且当用户单击后退按钮时

this.router.navigateByUrl(this.returnUrl); // Hint taken from Sasxa

这应该能够导航到上一页。考虑到用户直接登陆您的页面的情况,如果他使用 location.back 按下后退按钮,我觉得上述方法更安全,而不是使用 location.back ,它会将用户重定向到上一个页面,而不是您的网页。


需要导入 ActivatedRoute 并在 queryParams 订阅(例如 this.route.queryParams.subscribe)上使用它而不是 Router,但除此之外,似乎可行!
对我来说,即使在角度 4 中,它也可以与路由器本身一起正常工作
最佳答案,但在 Angular 5(最多 x?)中,您需要注入一个“ActivatedRoute”对象并在该对象上使用 queryParams,正如 Stephen Kaiser 已经说过的那样。
D
Derlin

在 RC4 中:

import {Location} from '@angular/common';

这是对答案的补充,但不是答案本身
A
Albert

自测试版 18 起:

import {Location} from 'angular2/platform/common';


D
Džan Operta

另一种解决方案

window.history.back();


对我有用 location.back() 也可以,但我不能用 --prod 编译
N
Naeem Bashir

我用这种方式:

import { Location } from '@angular/common'
import { Component, Input } from '@angular/core'

@Component({
    selector: 'Back_page',
    template: `<button  (click)="onBack()">Back</button>`,
})
export class BackPageComponent {
  constructor(private location: Location) { }

  onBack() {
    this.location.back();// <-- go back to previous location
  }
}

j
jprism

如果您使用最新的 Angular/TypeScript,请确保您明确导入

import { Location } from '@angular/common';

 onCancel() {
    this.location.back();
  }

不幸的是,答案已经在 5 年前给出,甚至错过了您在构造函数中定义 location 的部分
是的,不要忘记在您的构造函数()中定义:私有位置:位置
N
Niels Prins

我想出了这个,你也可以检查是否有前一页。确保在您的 appComponent 中使用该服务。

import { Injectable } from '@angular/core';
import { Location } from '@angular/common';
import { NavigationEnd, Router } from '@angular/router';

interface HistoryData {
  previousPage: string | null,
  currentPage: string | null,
}

@Injectable({ providedIn: 'root' })
export class GoBackService {

  private historyData: HistoryData = { previousPage: null, currentPage: null };

  constructor(private router: Router, private location: Location) {
    this.router.events.subscribe((event) => {
      if (event instanceof NavigationEnd) {
        this.historyData.previousPage = this.historyData.currentPage;
        this.historyData.currentPage = event.urlAfterRedirects;
      }
    });
  }

  public goBack(): void {
    if (this.historyData.previousPage) this.location.back();
  }

  public canGoBack(): boolean {
    return Boolean(this.historyData.previousPage);
  }

}

G
Gal Margalit

2022 利用您的应用程序路由 - 更多的是“角度方法”,而不是访问浏览器的位置对象以获取导航历史记录。想想为什么需要用户“返回”,以及“返回”在应用程序及其路由的更广泛上下文中意味着什么。

例如,从其子路由返回到父路由

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

您还可以阅读previous navigation

previousNavigation :之前成功的 Navigation 对象。只有一个以前的导航可用,因此这个以前的 Navigation 对象对于它自己的 previousNavigation 有一个空值。


S
Sangwin Gawande

只需使用 Location ,这是一种 Angular 服务,应用程序可以使用它与浏览器的 URL 进行交互。

导入它:

import { Location } from '@angular/common';

注入它:

constructor(private location: Location) { }

只需使用它:

goBack() {
    this.location.back(); // Navigates back in the platform's history
}

M
Mohammad Reza

是的,你可以做到。在你的打字稿组件上写下这段代码,尽情享受吧!

import { Location } from '@angular/common'
import { Component, Input } from '@angular/core'

@Component({
    selector: 'return_page',
    template: `<button mat-button (click)="onReturn()">Back</button>`,
})
export class ReturnPageComponent {
  constructor(private location: Location) { }

  onReturn() {
    this.location.back();
  }
}

Y
Yuriy Gyerts

如果历史记录为空,您也可以将此服务与后备功能一起使用

url-back.service.ts

import { Injectable } from '@angular/core';
import { Location } from '@angular/common';

import { Router } from '@angular/router';

const EMPTY_HISTORY_LENGTH = 2;

/**
 * This service helps to Navigate back to the prev page, and if no prev page,
 * will redirect to the fallback url.
 */
@Injectable()
export class UrlBackService {
  constructor(private router: Router, private location: Location) {}

  /**
   * This method will back you to the previous page,
   * if no previous page exists, will redirect you to the fallback url.
   * @param href - url, if tryNativeFirst is provided, this is fallback url
   * @param tryNativeFirst - try to go back natively using browser history state.
   */
  back(href: string, tryNativeFirst: boolean = false) {
    if (tryNativeFirst) {
      if (history.length === EMPTY_HISTORY_LENGTH) {
        this.router.navigate(UrlBackService.urlToArray(href));
      } else {
        this.location.back();
      }
    } else {
      this.router.navigate(UrlBackService.urlToArray(href));
    }
  }

  /**
   * In case that router.navigate method tries to escape all '/' in the string,
   * was decided to split string to array, and if URL starts or ends with slash - remove them, eg:
   * /my/url will be split to ['', 'my', 'url'], so we need to remove empty spaces use filter function.
   * @param href
   * @private
   */
  private static urlToArray(href: string) {
    return href.split('/').filter((notEmpty) => notEmpty);
  }
}

url-back.service.spec.ts

import { TestBed } from '@angular/core/testing';

import { UrlBackService } from './url-back.service';
import { Router } from '@angular/router';
import { Location } from '@angular/common';
import { RouterTestingModule } from '@angular/router/testing';

describe('UrlBackService', () => {
  let service: UrlBackService;
  let router: Router;
  let location: Location;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [RouterTestingModule],
      providers: [UrlBackService],
    });
    service = TestBed.inject(UrlBackService);
    router = TestBed.inject(Router);
    location = TestBed.inject(Location);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });

  it('no meter what history state is, it should be redirected to the /my/url', () => {
    spyOn(router, 'navigate');
    service.back('/my/url');
    expect(router.navigate).toHaveBeenCalledWith(['my', 'url']);
  });

  it('in case history is empty push to /my/url', () => {
    spyOn(router, 'navigate');
    service.back('/my/url', true);
    expect(router.navigate).toHaveBeenCalledWith(['my', 'url']);
  });

  it('in case history is NOT empty push to url1', () => {
    spyOn(location, 'back');
    window.history.pushState(null, '', 'url1');

    service.back('/my/url', true);
    expect(location.back).toHaveBeenCalled();
  });
});

R
Rojin Gharooni

试试 routerLink="../LASTPAGE"