Angular 教程:為英雄之旅添加路由支持-里程碑 6:異步路由

2022-07-05 11:34 更新

里程碑 6:異步路由

完成上面的里程碑后,應(yīng)用程序很自然地長(zhǎng)大了。在某一個(gè)時(shí)間點(diǎn),你將達(dá)到一個(gè)頂點(diǎn),應(yīng)用將會(huì)需要過(guò)多的時(shí)間來(lái)加載。

為了解決這個(gè)問(wèn)題,請(qǐng)使用異步路由,它會(huì)根據(jù)請(qǐng)求來(lái)惰性加載某些特性模塊。惰性加載有很多好處。

  • 你可以只在用戶請(qǐng)求時(shí)才加載某些特性區(qū)。
  • 對(duì)于那些只訪問(wèn)應(yīng)用程序某些區(qū)域的用戶,這樣能加快加載速度。
  • 你可以持續(xù)擴(kuò)充惰性加載特性區(qū)的功能,而不用增加初始加載的包體積。

你已經(jīng)完成了一部分。通過(guò)把應(yīng)用組織成一些模塊:?AppModule?、?HeroesModule?、?AdminModule ?和 ?CrisisCenterModule?,你已經(jīng)有了可用于實(shí)現(xiàn)惰性加載的候選者。

有些模塊(比如 ?AppModule?)必須在啟動(dòng)時(shí)加載,但其它的都可以而且應(yīng)該惰性加載。比如 ?AdminModule ?就只有少數(shù)已認(rèn)證的用戶才需要它,所以你應(yīng)該只有在正確的人請(qǐng)求它時(shí)才加載。

惰性加載路由配置

把 ?admin-routing.module.ts? 中的 ?admin ?路徑從 ?'admin'? 改為空路徑 ?''?。

可以用空路徑路由來(lái)對(duì)路由進(jìn)行分組,而不用往 URL 中添加額外的路徑片段。用戶仍舊訪問(wèn) ?/admin?,并且 ?AdminComponent ?仍然作為用來(lái)包含子路由的路由組件。

打開(kāi) ?AppRoutingModule?,并把一個(gè)新的 ?admin ?路由添加到它的 ?appRoutes ?數(shù)組中。

給它一個(gè) ?loadChildren ?屬性(替換掉 ?children ?屬性)。?loadChildren ?屬性接收一個(gè)函數(shù),該函數(shù)使用瀏覽器內(nèi)置的動(dòng)態(tài)導(dǎo)入語(yǔ)法 ?import('...')? 來(lái)惰性加載代碼,并返回一個(gè)承諾(Promise)。其路徑是 ?AdminModule ?的位置(相對(duì)于應(yīng)用的根目錄)。當(dāng)代碼請(qǐng)求并加載完畢后,這個(gè) ?Promise ?就會(huì)解析成一個(gè)包含 ?NgModule ?的對(duì)象,也就是 ?AdminModule?。

{
  path: 'admin',
  loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
},
注意:
當(dāng)使用絕對(duì)路徑時(shí),?NgModule ?的文件位置必須以 ?src/app? 開(kāi)頭,以便正確解析。對(duì)于自定義的 使用絕對(duì)路徑的路徑映射表,你必須在項(xiàng)目的 ?tsconfig.json? 中必須配置好 ?baseUrl ?和 ?paths ?屬性。

當(dāng)路由器導(dǎo)航到這個(gè)路由時(shí),它會(huì)用 ?loadChildren ?字符串來(lái)動(dòng)態(tài)加載 ?AdminModule?,然后把 ?AdminModule ?添加到當(dāng)前的路由配置中,最后,它把所請(qǐng)求的路由加載到目標(biāo) ?admin ?組件中。

惰性加載和重新配置工作只會(huì)發(fā)生一次,也就是在該路由首次被請(qǐng)求時(shí)。在后續(xù)的請(qǐng)求中,該模塊和路由都是立即可用的。

最后一步是把管理特性區(qū)從主應(yīng)用中完全分離開(kāi)。根模塊 ?AppModule ?既不能加載也不能引用 ?AdminModule ?及其文件。

在 ?app.module.ts? 中,從頂部移除 ?AdminModule ?的導(dǎo)入語(yǔ)句,并且從 NgModule 的 ?imports ?數(shù)組中移除 ?AdminModule?。

CanLoad:保護(hù)對(duì)特性模塊的未授權(quán)加載

你已經(jīng)使用 ?CanActivate ?保護(hù) ?AdminModule ?了,它會(huì)阻止未授權(quán)用戶訪問(wèn)管理特性區(qū)。如果用戶未登錄,它就會(huì)跳轉(zhuǎn)到登錄頁(yè)。

但是路由器仍然會(huì)加載 ?AdminModule ?—— 即使用戶無(wú)法訪問(wèn)它的任何一個(gè)組件。理想的方式是,只有在用戶已登錄的情況下你才加載 ?AdminModule?。

添加一個(gè) ?CanLoad ?守衛(wèi),它只在用戶已登錄并且嘗試訪問(wèn)管理特性區(qū)的時(shí)候,才加載 ?AdminModule ?一次。

現(xiàn)有的 ?AuthGuard ?的 ?checkLogin()? 方法中已經(jīng)有了支持 ?CanLoad ?守衛(wèi)的基礎(chǔ)邏輯。

  1. 打開(kāi) ?auth.guard.ts?。
  2. 從 ?@angular/router? 導(dǎo)入 ?CanLoad ?接口。
  3. 把它添加到 ?AuthGuard ?類(lèi)的 ?implements ?列表中。
  4. 然后像下面這樣實(shí)現(xiàn) ?canLoad()?:
canLoad(route: Route): boolean {
  const url = `/${route.path}`;

  return this.checkLogin(url);
}

路由器會(huì)把 ?canLoad()? 方法的 ?route ?參數(shù)設(shè)置為準(zhǔn)備訪問(wèn)的目標(biāo) URL。如果用戶已經(jīng)登錄了,?checkLogin()? 方法就會(huì)重定向到那個(gè) URL。

現(xiàn)在,把 ?AuthGuard ?導(dǎo)入到 ?AppRoutingModule ?中,并把 ?AuthGuard ?添加到 ?admin ?路由的 ?canLoad ?數(shù)組中。完整的 ?admin ?路由是這樣的:

{
  path: 'admin',
  loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
  canLoad: [AuthGuard]
},

預(yù)加載:特性區(qū)的后臺(tái)加載

除了按需加載模塊外,還可以通過(guò)預(yù)加載方式異步加載模塊。

當(dāng)應(yīng)用啟動(dòng)時(shí),?AppModule ?被急性加載,這意味著它會(huì)立即加載。而 ?AdminModule? 只在用戶點(diǎn)擊鏈接時(shí)加載,這叫做惰性加載。

預(yù)加載允許你在后臺(tái)加載模塊,以便當(dāng)用戶激活某個(gè)特定的路由時(shí),就可以渲染這些數(shù)據(jù)了??紤]一下危機(jī)中心。它不是用戶看到的第一個(gè)視圖。默認(rèn)情況下,英雄列表才是第一個(gè)視圖。為了獲得最小的初始有效負(fù)載和最快的啟動(dòng)時(shí)間,你應(yīng)該急性加載 ?AppModule ?和 ?HeroesModule?。

你可以惰性加載危機(jī)中心。但是,你幾乎可以肯定用戶會(huì)在啟動(dòng)應(yīng)用之后的幾分鐘內(nèi)訪問(wèn)危機(jī)中心。理想情況下,應(yīng)用啟動(dòng)時(shí)應(yīng)該只加載 ?AppModule ?和 ?HeroesModule?,然后幾乎立即開(kāi)始后臺(tái)加載 ?CrisisCenterModule?。在用戶瀏覽到危機(jī)中心之前,該模塊應(yīng)該已經(jīng)加載完畢,可供訪問(wèn)了。

預(yù)加載的工作原理

在每次成功的導(dǎo)航后,路由器會(huì)在自己的配置中查找尚未加載并且可以預(yù)加載的模塊。是否加載某個(gè)模塊,以及要加載哪些模塊,取決于預(yù)加載策略

?Router ?提供了兩種預(yù)加載策略:

策略

詳情

不預(yù)加載

這是默認(rèn)值。惰性加載的特性區(qū)仍然會(huì)按需加載。

預(yù)加載

預(yù)加載所有惰性加載的特性區(qū)。

路由器或者完全不預(yù)加載或者預(yù)加載每個(gè)惰性加載模塊。 路由器還支持自定義預(yù)加載策略,以便完全控制要預(yù)加載哪些模塊以及何時(shí)加載。

本節(jié)將指導(dǎo)你把 ?CrisisCenterModule ?改成惰性加載的,并使用 ?PreloadAllModules ?策略來(lái)預(yù)加載所有惰性加載模塊。

惰性加載危機(jī)中心

修改路由配置,來(lái)惰性加載 ?CrisisCenterModule?。修改的步驟和配置惰性加載 ?AdminModule ?時(shí)一樣。

  1. 把 ?CrisisCenterRoutingModule ?中的路徑從 ?crisis-center? 改為空字符串。
  2. 往 ?AppRoutingModule ?中添加一個(gè) ?crisis-center? 路由。
  3. 設(shè)置 ?loadChildren ?字符串來(lái)加載 ?CrisisCenterModule?。
  4. 從 ?app.module.ts? 中移除所有對(duì) ?CrisisCenterModule ?的引用。

下面是打開(kāi)預(yù)加載之前的模塊修改版:

  • app.module.ts
  • import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { FormsModule } from '@angular/forms';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    
    import { Router } from '@angular/router';
    
    import { AppComponent } from './app.component';
    import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
    import { ComposeMessageComponent } from './compose-message/compose-message.component';
    
    import { AppRoutingModule } from './app-routing.module';
    import { HeroesModule } from './heroes/heroes.module';
    import { AuthModule } from './auth/auth.module';
    
    @NgModule({
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        FormsModule,
        HeroesModule,
        AuthModule,
        AppRoutingModule,
      ],
      declarations: [
        AppComponent,
        ComposeMessageComponent,
        PageNotFoundComponent
      ],
      bootstrap: [ AppComponent ]
    })
    export class AppModule {
    }
  • app-routing.module.ts
  • import { NgModule } from '@angular/core';
    import {
      RouterModule, Routes,
    } from '@angular/router';
    
    import { ComposeMessageComponent } from './compose-message/compose-message.component';
    import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
    
    import { AuthGuard } from './auth/auth.guard';
    
    const appRoutes: Routes = [
      {
        path: 'compose',
        component: ComposeMessageComponent,
        outlet: 'popup'
      },
      {
        path: 'admin',
        loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
        canLoad: [AuthGuard]
      },
      {
        path: 'crisis-center',
        loadChildren: () => import('./crisis-center/crisis-center.module').then(m => m.CrisisCenterModule)
      },
      { path: '',   redirectTo: '/heroes', pathMatch: 'full' },
      { path: '**', component: PageNotFoundComponent }
    ];
    
    @NgModule({
      imports: [
        RouterModule.forRoot(
          appRoutes,
        )
      ],
      exports: [
        RouterModule
      ]
    })
    export class AppRoutingModule {}
  • crisis-center-routing.module.ts
  • import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';
    
    import { CrisisCenterHomeComponent } from './crisis-center-home/crisis-center-home.component';
    import { CrisisListComponent } from './crisis-list/crisis-list.component';
    import { CrisisCenterComponent } from './crisis-center/crisis-center.component';
    import { CrisisDetailComponent } from './crisis-detail/crisis-detail.component';
    
    import { CanDeactivateGuard } from '../can-deactivate.guard';
    import { CrisisDetailResolverService } from './crisis-detail-resolver.service';
    
    const crisisCenterRoutes: Routes = [
      {
        path: '',
        component: CrisisCenterComponent,
        children: [
          {
            path: '',
            component: CrisisListComponent,
            children: [
              {
                path: ':id',
                component: CrisisDetailComponent,
                canDeactivate: [CanDeactivateGuard],
                resolve: {
                  crisis: CrisisDetailResolverService
                }
              },
              {
                path: '',
                component: CrisisCenterHomeComponent
              }
            ]
          }
        ]
      }
    ];
    
    @NgModule({
      imports: [
        RouterModule.forChild(crisisCenterRoutes)
      ],
      exports: [
        RouterModule
      ]
    })
    export class CrisisCenterRoutingModule { }

你可以現(xiàn)在嘗試它,并確認(rèn)在點(diǎn)擊了“Crisis Center”按鈕之后加載了 ?CrisisCenterModule?。

要為所有惰性加載模塊啟用預(yù)加載功能,請(qǐng)從 Angular 的路由模塊中導(dǎo)入 ?PreloadAllModules?。

?RouterModule.forRoot()? 方法的第二個(gè)參數(shù)接受一個(gè)附加配置選項(xiàng)對(duì)象。?preloadingStrategy ?就是其中之一。把 ?PreloadAllModules ?添加到 ?forRoot()? 調(diào)用中:

RouterModule.forRoot(
  appRoutes,
  {
    enableTracing: true, // <-- debugging purposes only
    preloadingStrategy: PreloadAllModules
  }
)

這項(xiàng)配置會(huì)讓 ?Router ?預(yù)加載器立即加載所有惰性加載路由(帶 ?loadChildren ?屬性的路由)。

當(dāng)訪問(wèn) ?http://localhost:4200? 時(shí),?/heroes? 路由立即隨之啟動(dòng),并且路由器在加載了 ?HeroesModule ?之后立即開(kāi)始加載 ?CrisisCenterModule?。

目前,?AdminModule ?并沒(méi)有預(yù)加載,因?yàn)?nbsp;?CanLoad ?阻塞了它。

CanLoad 會(huì)阻塞預(yù)加載

?PreloadAllModules ?策略不會(huì)加載被?CanLoad?守衛(wèi)所保護(hù)的特性區(qū)。

幾步之前,你剛剛給 ?AdminModule ?中的路由添加了 ?CanLoad ?守衛(wèi),以阻塞加載那個(gè)模塊,直到用戶認(rèn)證結(jié)束。?CanLoad ?守衛(wèi)的優(yōu)先級(jí)高于預(yù)加載策略。

如果你要加載一個(gè)模塊并且保護(hù)它防止未授權(quán)訪問(wèn),請(qǐng)移除 ?canLoad ?守衛(wèi),只單獨(dú)依賴(lài)?CanActivate?守衛(wèi)。

自定義預(yù)加載策略

在很多場(chǎng)景下,預(yù)加載的每個(gè)惰性加載模塊都能正常工作。但是,考慮到低帶寬和用戶指標(biāo)等因素,可以為特定的特性模塊使用自定義預(yù)加載策略。

本節(jié)將指導(dǎo)你添加一個(gè)自定義策略,它只預(yù)加載 ?data.preload? 標(biāo)志為 ?true ?路由?;叵胍幌?,你可以在路由的 ?data ?屬性中添加任何東西。

在 ?AppRoutingModule ?的 ?crisis-center? 路由中設(shè)置 ?data.preload? 標(biāo)志。

{
  path: 'crisis-center',
  loadChildren: () => import('./crisis-center/crisis-center.module').then(m => m.CrisisCenterModule),
  data: { preload: true }
},

生成一個(gè)新的 ?SelectivePreloadingStrategy ?服務(wù)。

ng generate service selective-preloading-strategy

使用下列內(nèi)容替換 ?selective-preloading-strategy.service.ts?:

import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class SelectivePreloadingStrategyService implements PreloadingStrategy {
  preloadedModules: string[] = [];

  preload(route: Route, load: () => Observable<any>): Observable<any> {
    if (route.data?.['preload'] && route.path != null) {
      // add the route path to the preloaded module array
      this.preloadedModules.push(route.path);

      // log the route path to the console
      console.log('Preloaded: ' + route.path);

      return load();
    } else {
      return of(null);
    }
  }
}

?SelectivePreloadingStrategyService ?實(shí)現(xiàn)了 ?PreloadingStrategy?,它有一個(gè)方法 ?preload()?。

路由器會(huì)用兩個(gè)參數(shù)來(lái)調(diào)用 ?preload()? 方法:

  1. 要加載的路由。
  2. 一個(gè)加載器(loader)函數(shù),它能異步加載帶路由的模塊。

?preload ?的實(shí)現(xiàn)要返回一個(gè) ?Observable?。如果該路由應(yīng)該預(yù)加載,它就會(huì)返回調(diào)用加載器函數(shù)所返回的 ?Observable?。如果該路由應(yīng)該預(yù)加載,它就返回一個(gè) ?null ?值的 ?Observable ?對(duì)象。

在這個(gè)例子中,如果路由的 ?data.preload? 標(biāo)志是真值,則 ?preload()? 方法會(huì)加載該路由。

它的副作用是 ?SelectivePreloadingStrategyService ?會(huì)把所選路由的 ?path ?記錄在它的公共數(shù)組 ?preloadedModules ?中。

很快,你就會(huì)擴(kuò)展 ?AdminDashboardComponent ?來(lái)注入該服務(wù),并且顯示它的 ?preloadedModules ?數(shù)組。

但是首先,要對(duì) ?AppRoutingModule ?做少量修改。

  1. 把 ?SelectivePreloadingStrategyService ?導(dǎo)入到 ?AppRoutingModule ?中。
  2. 把 ?PreloadAllModules ?策略替換成對(duì) ?forRoot()? 的調(diào)用,并且傳入這個(gè) ?SelectivePreloadingStrategyService?。

現(xiàn)在,編輯 ?AdminDashboardComponent ?以顯示這些預(yù)加載路由的日志。

  1. 導(dǎo)入 ?SelectivePreloadingStrategyService?(它是一個(gè)服務(wù))。
  2. 把它注入到儀表盤(pán)的構(gòu)造函數(shù)中。
  3. 修改模板來(lái)顯示這個(gè)策略服務(wù)的 ?preloadedModules ?數(shù)組。

現(xiàn)在文件如下:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { SelectivePreloadingStrategyService } from '../../selective-preloading-strategy.service';

@Component({
  selector: 'app-admin-dashboard',
  templateUrl: './admin-dashboard.component.html',
  styleUrls: ['./admin-dashboard.component.css']
})
export class AdminDashboardComponent implements OnInit {
  sessionId!: Observable<string>;
  token!: Observable<string>;
  modules: string[] = [];

  constructor(
    private route: ActivatedRoute,
    preloadStrategy: SelectivePreloadingStrategyService
  ) {
    this.modules = preloadStrategy.preloadedModules;
  }

  ngOnInit() {
    // Capture the session ID if available
    this.sessionId = this.route
      .queryParamMap
      .pipe(map(params => params.get('session_id') || 'None'));

    // Capture the fragment if available
    this.token = this.route
      .fragment
      .pipe(map(fragment => fragment || 'None'));
  }
}

一旦應(yīng)用加載完了初始路由,?CrisisCenterModule ?也被預(yù)加載了。通過(guò) ?Admin ?特性區(qū)中的記錄就可以驗(yàn)證它,“Preloaded Modules”中列出了 ?crisis-center?。它也被記錄到了瀏覽器的控制臺(tái)。

使用重定向遷移 URL

你已經(jīng)設(shè)置好了路由,并且用命令式和聲明式的方式導(dǎo)航到了很多不同的路由。但是,任何應(yīng)用的需求都會(huì)隨著時(shí)間而改變。你把鏈接 ?/heroes? 和 ?hero/:id? 指向了 ?HeroListComponent ?和 ?HeroDetailComponent ?組件。如果有這樣一個(gè)需求,要把鏈接 ?heroes ?變成 ?superheroes?,你可能仍然希望以前的 URL 能正常導(dǎo)航。但你也不想在應(yīng)用中找到并修改每一個(gè)鏈接,這時(shí)候,重定向就可以省去這些瑣碎的重構(gòu)工作。

把 /heroes 改為 /superheroes

本節(jié)將指導(dǎo)你將 ?Hero ?路由遷移到新的 URL。在導(dǎo)航之前,?Router ?會(huì)檢查路由配置中的重定向語(yǔ)句,以便將來(lái)按需觸發(fā)重定向。要支持這種修改,你就要在 ?heroes-routing.module? 文件中把老的路由重定向到新的路由。

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { HeroListComponent } from './hero-list/hero-list.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';

const heroesRoutes: Routes = [
  { path: 'heroes', redirectTo: '/superheroes' },
  { path: 'hero/:id', redirectTo: '/superhero/:id' },
  { path: 'superheroes',  component: HeroListComponent, data: { animation: 'heroes' } },
  { path: 'superhero/:id', component: HeroDetailComponent, data: { animation: 'hero' } }
];

@NgModule({
  imports: [
    RouterModule.forChild(heroesRoutes)
  ],
  exports: [
    RouterModule
  ]
})
export class HeroesRoutingModule { }

注意,這里有兩種類(lèi)型的重定向。第一種是不帶參數(shù)的從 ?/heroes? 重定向到 ?/superheroes?。這是一種非常直觀的重定向。第二種是從 ?/hero/:id? 重定向到 ?/superhero/:id?,它還要包含一個(gè) ?:id? 路由參數(shù)。路由器重定向時(shí)使用強(qiáng)大的模式匹配功能,這樣,路由器就會(huì)檢查 URL,并且把 ?path ?中帶的路由參數(shù)替換成相應(yīng)的目標(biāo)形式。以前,你導(dǎo)航到形如 ?/hero/15? 的 URL 時(shí),帶了一個(gè)路由參數(shù) ?id?,它的值是 ?15?。

在重定向的時(shí)候,路由器還支持查詢參數(shù)片段(fragment)。
  • 當(dāng)使用絕對(duì)地址重定向時(shí),路由器將會(huì)使用路由配置的 ?redirectTo ?屬性中規(guī)定的查詢參數(shù)和片段。
  • 當(dāng)使用相對(duì)地址重定向時(shí),路由器將會(huì)使用源地址(跳轉(zhuǎn)前的地址)中的查詢參數(shù)和片段。

目前,空路徑被重定向到了 ?/heroes?,它又被重定向到了 ?/superheroes?。這樣不行,因?yàn)?nbsp;?Router ?在每一層的路由配置中只會(huì)處理一次重定向。這樣可以防止出現(xiàn)無(wú)限循環(huán)的重定向。

所以,你要在 ?app-routing.module.ts? 中修改空路徑路由,讓它重定向到 ?/superheroes?。

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { ComposeMessageComponent } from './compose-message/compose-message.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';

import { AuthGuard } from './auth/auth.guard';
import { SelectivePreloadingStrategyService } from './selective-preloading-strategy.service';

const appRoutes: Routes = [
  {
    path: 'compose',
    component: ComposeMessageComponent,
    outlet: 'popup'
  },
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
    canLoad: [AuthGuard]
  },
  {
    path: 'crisis-center',
    loadChildren: () => import('./crisis-center/crisis-center.module').then(m => m.CrisisCenterModule),
    data: { preload: true }
  },
  { path: '',   redirectTo: '/superheroes', pathMatch: 'full' },
  { path: '**', component: PageNotFoundComponent }
];

@NgModule({
  imports: [
    RouterModule.forRoot(
      appRoutes,
      {
        enableTracing: false, // <-- debugging purposes only
        preloadingStrategy: SelectivePreloadingStrategyService,
      }
    )
  ],
  exports: [
    RouterModule
  ]
})
export class AppRoutingModule { }

由于 ?routerLink ?與路由配置無(wú)關(guān),所以你要修改相關(guān)的路由鏈接,以便在新的路由激活時(shí),它們也能保持激活狀態(tài)。還要修改 ?app.component.ts? 模板中的 ?/heroes? 這個(gè) ?routerLink?。

<div class="wrapper">
  <h1 class="title">Angular Router</h1>
  <nav>
    <a routerLink="/crisis-center" routerLinkActive="active" ariaCurrentWhenActive="page">Crisis Center</a>
    <a routerLink="/superheroes" routerLinkActive="active" ariaCurrentWhenActive="page">Heroes</a>
    <a routerLink="/admin" routerLinkActive="active" ariaCurrentWhenActive="page">Admin</a>
    <a routerLink="/login" routerLinkActive="active" ariaCurrentWhenActive="page">Login</a>
    <a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
  </nav>
  <div [@routeAnimation]="getRouteAnimationData()">
    <router-outlet></router-outlet>
  </div>
  <router-outlet name="popup"></router-outlet>
</div>

修改 ?hero-detail.component.ts? 中的 ?goToHeroes()? 方法,使用可選的路由參數(shù)導(dǎo)航回 ?/superheroes?。

gotoHeroes(hero: Hero) {
  const heroId = hero ? hero.id : null;
  // Pass along the hero id if available
  // so that the HeroList component can select that hero.
  // Include a junk 'foo' property for fun.
  this.router.navigate(['/superheroes', { id: heroId, foo: 'foo' }]);
}

當(dāng)這些重定向設(shè)置好之后,所有以前的路由都指向了它們的新目標(biāo),并且每個(gè) URL 也仍然能正常工作。

審查路由器配置

要確定你的路由是否真的按照正確的順序執(zhí)行的,你可以審查路由器的配置。

可以通過(guò)注入路由器并在控制臺(tái)中記錄其 ?config ?屬性來(lái)實(shí)現(xiàn)。比如,把 ?AppModule ?修改為這樣,并在瀏覽器的控制臺(tái)窗口中查看最終的路由配置。

export class AppModule {
  // Diagnostic only: inspect router configuration
  constructor(router: Router) {
    // Use a custom replacer to display function names in the route configs
    const replacer = (key, value) => (typeof value === 'function') ? value.name : value;

    console.log('Routes: ', JSON.stringify(router.config, replacer, 2));
  }
}

最終的應(yīng)用

對(duì)這個(gè)已完成的路由器應(yīng)用,參見(jiàn) 現(xiàn)場(chǎng)演練 / 下載范例的最終代碼。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)