简体   繁体   English

Angular 2 路由器事件监听器

[英]Angular 2 router event listener

How to listen state change in Angular 2 router? Angular 2路由器中如何监听state变化?

In Angular 1.x I used this event:在 Angular 1.x 中我使用了这个事件:

$rootScope.$on('$stateChangeStart',
    function(event,toState,toParams,fromState,fromParams, options){ ... })

So, if I use this eventlistener in Angular 2:所以,如果我在 Angular 2 中使用这个事件监听器:

window.addEventListener("hashchange", () => {return console.log('ok')}, false);

it isn't return 'ok', then change state from JS, only then browser history.back() function run.它不返回“确定”,然后从 JS 更改 state,然后浏览器 history.back() function 运行。

Use router.subscribe() function as the service:使用 router.subscribe() function 作为服务:

import {Injectable} from 'angular2/core';
import {Router} from 'angular2/router';

@Injectable()
export class SubscribeService {
    constructor (private _router: Router) {
        this._router.subscribe(val => {
            console.info(val, '<-- subscribe func');
        })
    }
}

Inject service in component which init in routing:在路由中初始化的组件中注入服务:

import {Component} from 'angular2/core';
import {Router} from 'angular2/router';

@Component({
    selector: 'main',
    templateUrl: '../templates/main.html',
    providers: [SubscribeService]
})
export class MainComponent {
    constructor (private subscribeService: SubscribeService) {}
}

I inject this service in other components such as in this example.我将此服务注入到其他组件中,例如本例中的组件。 Then I change state, console.info() in service not working.然后我更改 state,console.info() in service not working。

What I do wrong?我做错了什么?

new router新路由器

constructor(router:Router) {
  router.events.subscribe(event:Event => {
    if(event instanceof NavigationStart) {
    }
    // NavigationEnd
    // NavigationCancel
    // NavigationError
    // RoutesRecognized
  });
}

old老的

Inject the Router and subscribe to route change events注入路由器并订阅路由变化事件

import {Router} from 'angular2/router';

class MyComponent {
  constructor(router:Router) {
    router.subscribe(...)
  }
}

NOTE笔记

For the new router, don't forget to import NavigationStart from router module对于新的路由器,不要忘记从router模块中导入NavigationStart

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

because if you don't import it instanceof will not work and an error NavigationStart is not defined will rise.因为如果你不导入它, instanceof将不起作用,并且NavigationStart is not defined会出现错误。

See also也可以看看

You can also filter events with filter() .您还可以使用filter()过滤事件。

But don't just use filter(e => e is NavigationEnd)但不要使用filter(e => e is NavigationEnd)

A much better solution is to add a 'type guard' to filter() like this:更好的解决方案是向filter()添加一个“类型保护”,如下所示:

 filter((e): e is NavigationEnd => e instanceof NavigationEnd), 

It contains two things:它包含两件事:

  • e is NavigationEnd this is the assertion you're defining a function for (this is typescript syntax and is completely stripped out of the transpiled javascript) e is NavigationEnd这是您为其定义函数的断言(这是打字稿语法,完全从转译的 javascript 中剥离出来)
  • e instanceof NavigationEnd this is the actual runtime code that checks the type e instanceof NavigationEnd这是检查类型的实际运行时代码

The nice thing with this is that operators further down 'the pipe', like map below now know the type is NavigationEnd , but without the type-guard you'd have a type Event .这样做的好处是操作员在“管道”下方,例如下面的map ,现在知道类型是NavigationEnd ,但是如果没有类型保护,您将拥有类型Event

If you only need to check for one event type then this is the cleanest way to do so.如果您只需要检查一种事件类型,那么这是最简洁的方法。 This also appears to be necessary in strict mode to avoid compiler errors.这在严格模式下似乎也是必要的,以避免编译器错误。

在此处输入图片说明

You can use instanceof as @GünterZöchbauer answered您可以使用@GünterZöchbauer回答的instanceof

this.router.events.subscribe(event => {
  if(event instanceof NavigationStart) {
    // do something...
  }
}

or you can use a lazier approach, but remember constructor name can be changed easily while the function is still working!或者您可以使用更懒惰的方法,但请记住,在函数仍在工作时可以轻松更改构造函数名称!

this.router.events.subscribe(event => {
  if(event.constructor.name === "NavigationStart") {
    // do something...
  }
});

Straight from the docs直接来自文档

import {Event, RouterEvent, Router, NavigationEnd} from '@angular/router';

this.router.events.pipe(
  filter((e: any): e is RouterEvent => e instanceof RouterEvent)
).subscribe((evt: RouterEvent) => {
  if (evt instanceof NavigationEnd) {
    console.log(evt.url)
  }
})

Although the docs give the code filter((e: Event) but I changed this to filter((e: any) or you get linting errors in WebStorm.尽管文档提供了代码filter((e: Event)但我将其更改为filter((e: any)否则您会在 WebStorm 中遇到 linting 错误。

import { Router,NavigationEnd  } from '@angular/router';
constructor(private route:Router){

  this.routeEvent(this.route);

}
routeEvent(router: Router){
  router.events.subscribe(e => {
    if(e instanceof NavigationEnd){
      console.log(e)
    }
  });
}

The angular 2 router events has different classes, and what gets passed to the subscription from the router.events observable can either be NavigationEnd , NavigationCancel , NavigationError , or NavigationStart . angular 2 路由器事件有不同的类,从router.events observable 传递给订阅的router.events可以是NavigationEndNavigationCancelNavigationErrorNavigationStart The one that will actually trigger a routing update will be NavigationEnd .真正触发路由更新的是NavigationEnd

I would stay away from using instanceof or event.constructor.name because after minification the class names will get mangled it will not work correctly.我将远离使用instanceofevent.constructor.name因为在缩小后类名将被破坏,它将无法正常工作。

You can use the router's isActive function instead, shown here https://angular.io/docs/ts/latest/api/router/index/Router-class.html您可以改用路由器的isActive函数,如下所示https://angular.io/docs/ts/latest/api/router/index/Router-class.html

this.routerEventSubscription = this._router.events.subscribe((event: any) => {
  if (this._router.isActive(events.url, false)) { 
    // true if the url route is active
  }
}

in angular2, go to file "app.modules.ts"->imports在 angular2 中,转到文件“app.modules.ts”->imports

RouterModule.forRoot(
      appRoutes,
      { 
         enableTracing: true
      }
)

in enableTracing true show routeEvents in console in enableTracing false hide routeEvents in console在 enableTracing true 在控制台中显示 routeEvents 在 enableTracing false 在控制台中隐藏 routeEvents

With @bespunky/angular-zen this has become a lot simpler...有了@bespunky/angular-zen,这变得简单多了……

Basically, extend the RouteAware class and create an on<EventType>() method:基本上,扩展RouteAware类并创建一个on<EventType>()方法:

import { Component                                        } from '@angular/core';
import { NavigationStart, NavigationEnd, RoutesRecognized } from '@angular/router';
import { RouteAware                                       } from '@bespunky/angular-zen/router-x';

@Component({
    selector   : 'app-demo',
    templateUrl: './demo.component.html',
    styleUrls  : ['./demo.component.css']
})
export class DemoComponent extends RouteAware
{
    // ✨ Any router event can have a handler method.
    // See https://angular.io/guide/router#router-events for a complete list of angular's router events.

    // ✨ Use `this.router` to access the router
    // ✨ Use `this.route` to access the activated route
    // ✨ Use `this.componentBus` to access the RouterOutletComponentBus service
    
    protected onNavigationStart(event: NavigationStart): void
    {
        console.log(`Navigation started for: ${event.url}`);
    }

    protected onRoutesRecognized(event: RoutesRecognized): void
    {
        console.log('Recognized routes.');
    }
    
    protected onNavigationEnd(event: NavigationEnd): void
    {
        console.log(`Navigation ended for: ${event.url}`);
    }
}

Take a look at this answer: https://stackoverflow.com/a/64864103/4371525看看这个答案: https : //stackoverflow.com/a/64864103/4371525

阅读有关Angular路由事件的博客,您将获得有关路由事件和调试的详细信息。

To listen to all state changes, extend the default RouterOutlet and add your own logic in 'activate' and 'deactivate' handlers.要侦听所有状态更改,请扩展默认 RouterOutlet 并在“激活”和“停用”处理程序中添加您自己的逻辑。

import {Directive} from 'angular2/core';
import {Router, RouterOutlet, ComponentInstruction} from 'angular2/router';

@Directive({
  selector: 'router-outlet'
})

export class MyOwnRouterOutlet extends RouterOutlet {
  ...

  activate() {
    console.log('Hello from the new router outlet!');
  }
}

Copied from 'Custom Router Outlet' example here: https://auth0.com/blog/2016/01/25/angular-2-series-part-4-component-router-in-depth/从此处复制的“自定义路由器插座”示例: https : //auth0.com/blog/2016/01/25/angular-2-series-part-4-component-router-in-depth/

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM