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

时间:2016-08-24 20:44:47

标签: javascript angular angular-ui-router

我构建了一个使用router 3.0.0-beta.1在应用部分之间切换的应用。我还使用location.go()来模拟同一页面的子部分之间的切换。我使用<base href="/">和一些URL重写规则,以便在页面刷新时将所有路由重定向到index.html。这允许路由器接收所请求的子部分作为URL参数。基本上我设法避免使用HashLocationStrategy

routes.ts

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

如果我点击导航栏中的子部分,则会发生以下情况:

  • logation.go()使用必要的字符串更新网址,以指示当前小节
  • 自定义scrollTo()动画会将页面滚动到所请求小节的顶部。

如果我刷新页面,我使用先前定义的路线并提取必要的参数以恢复滚动到所请求的子部分。

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

除非单击后退按钮,否则一切正常。如果上一页是不同的部分,则应用程序路由器的行为与预期一致。但是,如果上一页/网址是子部分,则网址会更改为上一个网页,但UI中没有任何内容。如何检测后退按钮是否被按下以调用scrollTo()功能再次执行该作业?

我看到的大多数答案都依赖于事件onhashchange,但是这个事件在我的应用中没有被触发,因为我在URL中没有哈希...

11 个答案:

答案 0 :(得分:13)

我不知道答案是否过时,但在最新的Angular版本中,它们都不适合我。我所做的是通过将Angular事件监听器导入我的组件来添加一个Angular事件监听器:

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

然后在popstate对象上侦听window(正如Adrian推荐的那样):

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

这对我有用。

答案 1 :(得分:5)

要检测浏览器后退按钮,请单击 从&#39; @ angular / common导入platformlocation并将以下代码放在构造函数中:

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

答案 2 :(得分:5)

此问题的另一种选择是订阅Angular Router service发出的事件。由于我们正在处理路由,所以在我看来,使用Router事件更有意义。

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

我想指出的是,popstate是在浏览器上前后按下时发生的。因此,为了高效地执行此操作,您将必须找到一种方法来确定正在发生的情况。对我来说,那只是使用类型NavigationStartevent对象,它提供有关用户来自何处以及将要去往何处的信息。

答案 3 :(得分:4)

Angular文档直接在PlatformLocation类中声明...

  
      
  • 此类不应由应用程序开发人员直接使用。
  •   

我在构造函数中使用了LocationStrategy

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

答案 4 :(得分:4)

这是 Angular 11 的最新更新

你必须先从angular router导入NavigationStart

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

然后在构造函数中加入如下代码

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

答案 5 :(得分:3)

我同意Adrian Moisa的回答,

但您可以使用类PlatformLocation使用“更多Angular 2方式”注入您的组件或服务,然后您可以通过这种方式定义onPopState回调:

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

答案 6 :(得分:3)

更简单的方法-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());
}

答案 7 :(得分:2)

一种非常干净的方法是从rxjs导入'fromEvent'并以此方式使用它。

const elem = document.querySelector('p');

答案 8 :(得分:1)

使用onpopstate事件可以解决问题:

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

答案 9 :(得分:0)

老实说,我不知道您的用例。而且线程很旧。但这是Google的首个热门产品。如果其他人正在使用Angular 2和ui-router(就像您正在使用的那样)寻找它。

从技术上讲,这不是在检测后退按钮。进一步检测您作为开发人员是否触发了状态更改,或者用户是否自己更新了URL。

您可以添加自定义选项来更改状态,这可以通过uiSref和stateService.go完成。在转换中,您可以检查是否设置了此选项。 (不会在后退按钮点击等操作中设置)。

使用ui-sref

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

使用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}});
    }
}

您可以在任何过渡钩中检测到它,例如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?');
    }
}

答案 10 :(得分:0)

可以查看“window.history”的大小,如果大小为1则无法返回。

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