为啥 routerLink 和 router.navigate() 行为不同?

Posted

技术标签:

【中文标题】为啥 routerLink 和 router.navigate() 行为不同?【英文标题】:Why routerLink and router.navigate() act differently?为什么 routerLink 和 router.navigate() 行为不同? 【发布时间】:2018-01-19 18:47:54 【问题描述】:

html 中使用此代码时:

 <button [routerLink]="[ outlets:  flow: ['step1']  ]">click me to show step1</button>

它正确导航到'/child/(flow:step1)'!!!

尝试在 Typescript 中使用此代码时:

this.router.navigate([ outlets:  flow: ['step1']  ]);

它试图导航到错误的路径'/child(flow:step1)'!!!

它只是缺少斜线。

服务:

import  Injectable  from '@angular/core';
import  ActivatedRoute, Router  from '@angular/router';
import  EventBusService  from '../../../services/eventBus/eventBus.service';
import  RouterService  from '../../../services/router.service';

@Injectable()
export class FlowManagerService 
  constructor(private router: Router, private r: ActivatedRoute, private     eventBus: EventBusService, private routerService: RouterService) 
  

  initValidStep() 
    return     (parseInt(this.routerService.currentUrlName.substr(this.routerService.currentUrlName.indexOf('step'), 5).replace('step', ''), 10) === 1);
  

  goToFirstStep() 
    this.router.navigate([ outlets:  flow: ['step1']  ], relativeTo: this.r);

    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_NEXT);
    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_BACK);
  

  next(params) 
    const currentStep = this.routerService.currentUrlName.substr(this.routerService.currentUrlName.indexOf('step'), 5).replace('step', '');

    this.eventBus.emit(this.eventBus.globalEvents.FLOW.FLOW_STEP_CHANGE, (
      type: 'NEXT'
    ));
    this.router.navigate([ outlets:  flow: [`step$parseInt(currentStep, 10) + 1`, params]  ], relativeTo: this.r);

    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_NEXT);
    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_BACK);

  

  back(params) 
    const currentStep = this.routerService.currentUrlName.substr(this.routerService.currentUrlName.indexOf('step'), 5).replace('step', '');

    this.eventBus.emit(this.eventBus.globalEvents.FLOW.FLOW_STEP_CHANGE, (
      type: 'NEXT'
    ));
    this.router.navigate([ outlets:  flow: [`step$parseInt(currentStep, 10) - 1`, params]  ], relativeTo: this.r);

    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_NEXT);
    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_BACK);
  


这是使用上述服务的模块:

import  NgModule  from '@angular/core';
import  RouterModule  from '@angular/router';
import  FlowManagerService  from './service/flowManager.service';
import  CommonModule  from '@angular/common';

@NgModule(
  providers: [FlowManagerService],
  imports: [
    RouterModule,
    CommonModule
  ]
)
export class FlowManagerModule 


【问题讨论】:

【参考方案1】:

因为routerLink 隐式使用relativeTo 选项:

export class RouterLink 
  ...
  get urlTree(): UrlTree 
    return this.router.createUrlTree(this.commands, 
      relativeTo: this.route, <----

您需要在router.navigate 中明确提供:

constructor(private route: ActivatedRoute)

this.router.navigate([ outlets:  flow: ['step1']  ], relativeTo: this.route);

这是plunker 和完整的工作代码:

import  Component, NgModule  from '@angular/core'
import  BrowserModule  from '@angular/platform-browser'
import  RouterModule, Routes, Resolve, Router, ActivatedRoute  from '@angular/router';
import  APP_BASE_HREF  from '@angular/common';

@Component(
  selector: 'my-app',
  template: `
      <div id='my-app'>
          <router-outlet></router-outlet>
      </div>
  `,
)
export class App 
  constructor() 
  


@Component(
  selector: 'master-page',
  template: `
      <div id='master-page'>
          <div>Master Component</div>
          <button (click)='clickFirst()'>Inner Section 1</button>
          <button (click)='clickSecond()'>Inner Section 2</button>
          <router-outlet name='child'></router-outlet>
      </div>
  `
)
export class Master 
  constructor(private router: Router, private activeRouter: ActivatedRoute) 
  

  clickFirst() 
    this.router.navigate([outlets: child: 'details1'], relativeTo: this.activeRouter);
  


  clickSecond() 
    this.router.navigate([outlets: child: 'details2'], relativeTo: this.activeRouter);
  


@Component(
  template: `
      <div>
          This content is in the "Inner" page (1)
      </div>
  `
)
export class Details1 
  constructor() 
  


@Component(
  template: `
      <div>
          This content is in the "Inner" page (2)
      </div>
  `
)
export class Details2 
  constructor() 
  


const routes: Routes = [
  
    path: 'master',
    component: Master,
    children: [
      
        path: 'details1',
        component: Details1,
        outlet: 'child'
      ,
      
        path: 'details2',
        component: Details2,
        outlet: 'child'
      
    ]
  ,
  
    path: '',
    pathMatch: 'prefix',
    redirectTo: 'master'
  
];

@NgModule(
  imports: [BrowserModule, RouterModule.forRoot(routes)],
  declarations: [App, Master, Details1, Details2],
  providers: [
    provide: APP_BASE_HREF,
    useValue: '/'
  ],
  bootstrap: [App]
)
export class AppModule 

【讨论】:

你能设置一个 plunker 吗? link 这里...有一个基本插座和子插座...每次点击都应将组件插入一个子插座... @VladiIsakov,它对我来说很好用。在您的 plunker 中有一个错字,您应该使用 outletS,而不是 outlet。我在问题中发布了有效的app.ts 代码。 抱歉打错了,也为我工作......在我的代码中它仍然无法工作......它说“错误:无法匹配任何路由。URL段:'step1'” 我没有看到你的代码。如示例所示,您的问题的答案是正确的

以上是关于为啥 routerLink 和 router.navigate() 行为不同?的主要内容,如果未能解决你的问题,请参考以下文章

Angular - routerLink 和状态的问题

在Angular2 Dart中设置路由器和RouterLink的正确方法是啥

通过单击事件处理程序防止 routerLink 更改路由

Angular 4 中刷新页面和使用 routerLink 导航时的不同行为

在同一个按钮中使用 routerLink 和(单击)

Angular中的routerLink 跳转页面和默认路由