简体   繁体   English

Angular 2 如何使用路由器和 location.go() 检测后退按钮按下?

[英]Angular 2 How to detect back button press using router and location.go()?

I have built an app that uses router 3.0.0-beta.1 to switch between app sections.我构建了一个应用程序,它使用router 3.0.0-beta.1在应用程序部分之间切换。 I also use location.go() to emulate the switch between subsections of the same page.我还使用location.go()来模拟同一页面的子部分之间的切换。 I used <base href="/"> and a few URL rewrite rules in order to redirect all routes to index.html in case of page refresh.我使用了<base href="/">和一些 URL 重写规则,以便在页面刷新时将所有路由重定向到index.html This allows the router to receive the requested subsection as a URL param.这允许路由器接收请求的子部分作为 URL 参数。 Basically I have managed to avoid using the HashLocationStrategy .基本上我已经设法避免使用HashLocationStrategy

routes.ts路由.ts

export const routes: RouterConfig = [
    {
        path: '',
        redirectTo: '/catalog',
        pathMatch: 'full'
    },
    {
        path: 'catalog',
        component: CatalogComponent
    },
    {
        path: 'catalog/:topCategory',
        component: CatalogComponent
    },
    {
        path: 'summary',
        component: SummaryComponent
    }
];

If I click on a subsection in the navigation bar 2 things happen:如果我点击导航栏中的一个小节,会发生两件事:

  • logation.go() updates the URL with the necessary string in order to indicate the current subsection logation.go()使用必要的字符串更新 URL 以指示当前小节
  • A custom scrollTo() animation scrolls the page at the top of the requested subsection.自定义scrollTo()动画在请求的小节顶部滚动页面。

If I refresh the page I am using the previously defined route and extract the necessary parameter to restore scroll to the requested subsection.如果我刷新页面,我将使用先前定义的路由并提取必要的参数以恢复滚动到请求的子部分。

this._activatedRoute.params
    .map(params => params['topCategory'])
    .subscribe(topCategory => {
        if (typeof topCategory !== 'undefined' &&
            topCategory !== null
        ) {
            self.UiState.startArrowWasDismised = true;
            self.UiState.selectedTopCategory = topCategory;
        }
    });

All works fine except when I click the back button.一切正常,除非我单击后退按钮。 If previous page was a different section, the app router behaves as expected.如果上一页是不同的部分,则应用路由器会按预期运行。 However if the previous page/url was a subsection, the url changes to the previous one, but nothing happens in the UI.但是,如果前一个页面/url 是一个子部分,则 url 将更改为前一个,但 UI 中没有任何反应。 How can I detect if the back button was pressed in order to invoke the scrollTo() function to do it's job again?如何检测是否按下了后退按钮以调用scrollTo()函数再次完成它的工作?

Most answers I saw relly on the event onhashchange , but this event does not get fired in my app since I have no hash in the URL afterall...大多数的回答我relly看到了事件onhashchange ,但这一事件并没有在我的应用程序会被解雇,因为我在URL毕竟没有散...

I don't know if the other answers are dated, but neither of them worked well for me in Angular 7. What I did was add an Angular event listener by importing it into my component:我不知道其他答案是否过时,但它们在 Angular 7 中都不适合我。我所做的是通过将其导入到我的组件中来添加一个 Angular 事件侦听器:

import { HostListener } from '@angular/core';

and then listening for popstate on the window object (as Adrian recommended):然后在window对象上监听popstate (如 Adrian 推荐的那样):

  @HostListener('window:popstate', ['$event'])
  onPopState(event) {
    console.log('Back button pressed');
  }

This worked for me.这对我有用。

Another alternative for this issue would be to subscribe to the events emitted by the Angular Router service .此问题的另一种选择是订阅Angular Router 服务发出的事件。 Since we are dealing with routing, it seems to me that using Router events makes more sense.由于我们正在处理路由,在我看来使用 Router 事件更有意义。

constructor(router: Router) {
    router.events
      .subscribe((event: NavigationStart) => {
        if (event.navigationTrigger === 'popstate') {
          // Perform actions
        }
      });
}

I would like to note that popstate happens when pressing back and forward on the browser.我想指出,在浏览器上按后退和前进时会发生popstate So in order to do this efficiently, you would have to find a way to determine which one is occurring.因此,为了有效地执行此操作,您必须找到一种方法来确定正在发生的是哪一个。 For me, that was just using the event object of type NavigationStart which gives information about where the user is coming from and where they are going to.对我来说,那只是使用NavigationStart类型的event对象,它提供有关用户来自哪里以及他们要去哪里的信息。

To detect browser back button click import platformlocation from '@angular/common and place the below code in your constructor :要检测浏览器后退按钮,请单击 import platformlocation from '@angular/common 并将以下代码放入您的构造函数中:

 constructor(location: PlatformLocation) {
     location.onPopState(() => {
        alert(window.location);
     }); }

Angular documentation states directly in PlatformLocation class... Angular 文档直接在 PlatformLocation 类中声明...

  • This class should not be used directly by an application developer.应用程序开发人员不应直接使用此类。

I used LocationStrategy in the constructor我在构造函数中使用了 LocationStrategy

constructor(location: LocationStrategy) {
  location.onPopState(() => {
    alert(window.location);
  });
}

A great clean way is to import 'fromEvent' from rxjs and use it this way.一个非常干净的方法是从 rxjs 导入 'fromEvent' 并以这种方式使用它。

fromEvent(window, 'popstate')
  .subscribe((e) => {
    console.log(e, 'back button');
  });

This is the latest update for Angular 11这是 Angular 11 的最新更新

You have to first import NavigationStart from the angular router您必须首先从角度路由器导入 NavigationStart

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

Then add the following code to the constructor然后在构造函数中加入以下代码

constructor(private router: Router) {
  router.events.forEach((event) => {
    if(event instanceof NavigationStart) {
      if (event.navigationTrigger === 'popstate') {
        /* Do something here */
      }
    }
  });
}

Using onpopstate event did the trick:使用onpopstate事件可以解决问题:

window.addEventListener('popstate',
    // Add your callback here
    () => self.events.scrollToTopCategory.emit({ categId: self.state.selectedTopCategory })
);

I agree with Adrian Moisa answer,我同意 Adrian Moisa 的回答,

but you can use "more Angular 2 way" using class PlatformLocation by injecting to your component or service, then you can define onPopState callback this way:但是您可以通过注入到您的组件或服务中使用类PlatformLocation来使用“更多 Angular 2 方式”,然后您可以通过这种方式定义 onPopState 回调:

this.location.onPopState(()=>{
  // your code here...
  this.logger.debug('onpopstate event');
});

Simpler way - Link更简单的方法 -链接

import { PlatformLocation } from '@angular/common';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
...

constructor(
private platformLocation: PlatformLocation ,
private modalService: NgbModal
)
{
platformLocation.onPopState(() => this.modalService.dismissAll());
}

I honestly don't know your use case.老实说,我不知道您的用例。 And the thread is quite old.而且线程已经很老了。 But this was the first hit on Google.但这是谷歌的第一次成功。 And if someone else is looking for this with Angular 2 and ui-router (just as you are using).如果其他人正在使用 Angular 2 和 ui-router(就像您正在使用的那样)寻找这个。

It's not technically detecting the back button.它不是从技术上检测后退按钮。 It's more detecting whether you as a developer triggered the state change or whether the user updated the URL themselves.更多的是检测您作为开发人员是否触发了状态更改或用户是否自己更新了 URL。

You can add custom options to state changes, this can be done via uiSref and via stateService.go.您可以为状态更改添加自定义选项,这可以通过 uiSref 和 stateService.go 完成。 In your transitions, you can check whether this option is set.在您的过渡中,您可以检查是否设置了此选项。 (It won't be set on back button clicks and such). (它不会在点击后退按钮等时设置)。

Using ui-sref使用 ui-sref

    <a uiSref="destination-name" [uiOptions]="{custom: {viaSref: true}}">Bar</a>

Using state.go使用 state.go

import {StateService} from '@uirouter/core';

...

@Component(...)
export class MyComponent {

    constructor(
        private stateService: StateService
    ) {}

    public myAction(): void {
        this.stateService.go('destination-name', {}, {custom: {viaGo: true}});
    }
}

You can detect it in any transition hook, for example onSucces!您可以在任何过渡钩子中检测到它,例如 onSucces!

import {Transition, TransitionOptions, TransitionService} from '@uirouter/core';

...

@Component(...)
export class MyComponent implements OnInit {

    constructor(
        private transitionService: TransitionService
    ) {}

    public ngOnInit(): void {
        this.transitionService.onSuccess({}, (transition: Transition) => this.handleTransition(Transition));
    }

    private handleTransition(transition: Transition): void {
        let transitionOptions: TransitionOptions = transition.options();
        if (transitionOptions.custom?.viaSref) {
            console.log('viaSref!');
            return;
        }
        if (transitionOptions.custom?.viaGo) {
            console.log('viaGo!');
            return;
        }
        console.log('User transition?');
    }
}

You can check the size of "window.history", if the size is 1 you can't go back.您可以检查“window.history”的大小,如果大小为1,则无法返回。

isCanGoBack(){
    window.history.length > 1;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Location.go 后重新加载 Angular 6 路由参数 - Angular 6 route params reload after Location.go 如何在 React 中检测/处理后退按钮按下? - How to detect/handle back button press in React? Go 回反应路由器,并检测历史是否没有项目隐藏按钮 - Go back react router, and detect if the history have no items to hide the button 使用$ location使用角度返回 - Use $location to go back using angular 如何使用angular检测浏览器后退按钮单击事件? - How to detect browser back button click event using angular? Angular 2路由器的返回行为 - Go Back Behaviour of Angular 2 Router 如果使用window.location,用户不能按返回键返回上一页 - If window.location is used, user cannot press back button to go to previous page 检测是否使用流路由器通过浏览器后退按钮输入了路由 - Detect if route was entered via browser back button using flow router Angular ui-router:按下浏览器中的后退按钮,停止控制器重新加载 - Angular ui-router: stop controller from reloading on press of back button in the browser 在 SPA 中使用 React Router 来处理历史记录,包括浏览器后退按钮按下? - Using React Router in a SPA to handle history, including browser back button press?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM