在 Angular 2 的路由中,如何获取当前路由的组件参考?

9

有没有一种简洁的方法来获取当前路由组件的引用?

这个方法似乎可以工作,但看起来很hacky:

 this.router.currentInstruction.
  component.componentType.prototype.somePropertyOrFunction();

你想从哪里获取这个提示? - Thierry Templier
主要组件,我在这里设置我的路由。 - wannabeartist
1
我认为这是获取它的方法,但你可以删除“prototype”级别以调用它的方法;-) - Thierry Templier
实际上,“ComponentType”是“ComponentInstruction”类型,如果我只是删除原型,它就无法工作。 - wannabeartist
实际上,这不是组件实例,而是组件类型。这就是为什么你使用prototype,但它实际上并不是正确的实例。我添加了一个描述这一点的答案... - Thierry Templier
4个回答

6
实际上,您无法使用表达式访问与当前路由相关联的组件实例。您只能获取组件类型。这就是为什么您需要使用原型,但是您获得的是对函数的引用,而不是对组件实例方法的引用。
主要的影响将是如果在方法中使用,则关键字“this”将为undefined。
要访问与当前路由相关联的组件实例,您可以利用OnActivate钩子接口,在激活路由时将此实例设置到共享服务中:
@Component({
  selector: 'some-cmp',
  template: `
    <div>routerOnActivate: {{log}}</div>
  `})
  export class SomeCmp implements OnActivate {
    constructor(private service:RouteStateService) {
    }

    routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) {
      this.service.setCurrentRouteComponent(this);
    }
 }

然后您就可以通过以下方式访问组件实例:
var component = this.service.getCurrentRouteComponent();

4
有趣,为什么在 ActivatedRoute 中没有提及组件实例,有时将其放在那里会非常方便。 - pleerock

4

可以使用RouterOutletMap访问组件实例,它是Angular使用的一种有状态服务,用于存储由router-outlet指令渲染的实例。您可能需要以下类型:

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

顶级outletMaprouter的属性,但在TS中不可见,因此您可能需要将其转换为any

constructor(private router:Router) {
    const rootOutletMap:RouterOutletMap = (<any>this.router).outletMap;
}

RouterOutletMap 是一个 JavaScript 对象,它有一个属性 _outlets。这个 _outlets 是一个哈希映射对象,通过出口名称包含 RouterOutlet 实例。如果一个出口没有名称,它将是“primary”。在获取了 RouterOutlet 之后,您可以获取组件实例:

const rootOutletMap:RouterOutletMap = (<any>this.router).outletMap,
      outletsHash = (<any>rootOutletMap)._outlets,
      primaryOutlet:RouteOutlet = outletsHash['primary'], // 'primary' is the default name

      component = primaryOutlet.component; // <-- this is the instance

RouterOutletMap 是一棵树,因此根映射具有对子项的引用,以此类推。如果需要,您可以组织查找过程以找到特定路由的组件。以下是递归组件提取的示例:

// returns an array of all the router-outlets component currently rendered
private getComponentsChain(routerOutletMap: RouterOutletMap) {
    const outlets: any = (<any>routerOutletMap)._outlets,
          outletsList = [],
          components = [];

    _.forOwn(outlets, (value: RouterOutlet, key: string) => {
        outletsList.push(value);
        components.push(value.component);
    });

    const recursiveComponents = _.flatMap(
        outletsList,
        (o: RouterOutlet) => this.getComponentsChain(o.outletMap));

    return [...components, ...recursiveComponents];
}

/* ...then somewhere in component: */
console.log(this.getComponentsChain((<any>this.router).outletMap));

如果您选择这种方式,请注意以下几点:

  • 它使用了非公共的Angular功能,因此将来可能会发生变化;
  • 路由器出口具有自己的生命周期,如果您在错误的时刻选择它,可能会出现“出口未激活”的错误。

1

我发现的唯一简短但不太优美的方法是这样的(适用于Angular 4、6、7、8):

const currentComponent = (router as any).rootContexts.contexts 
  && (router as any).rootContexts.contexts.get('primary')
  && (router as any).rootContexts.contexts.get('primary').outlet.component;

注意:这是一个 HACK,如果您有多个路由器出口等,则可能无法正常工作。


-2

你可以从CanActivate守卫中获取组件的类型。例如:

    @Injectable()
    export class MyGuard: CanActivate
    {
      canActivate(route: ActivatedRouteSnapshot) : boolean{
         let componentType = route.routeConfig.component;
      }
    }

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