Route 異步路由

2020-07-08 11:47 更新

完成上面的里程碑后,應(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)用組織成一些模塊:AppModuleHeroesModule、AdminModuleCrisisCenterModule, 你已經(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:"app-routing.module.ts (load children)" 。

{
  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" 中必須配置好 baseUrlpaths 屬性。

當(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)求中,該模塊和路由都是立即可用的。

Angular 提供一個(gè)內(nèi)置模塊加載器,支持SystemJS 來(lái)異步加載模塊。如果你使用其它捆綁工具比如 Webpack,則使用 Webpack 的機(jī)制來(lái)異步加載模塊。

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

在 "app.module.ts" 中,從頂部移除 AdminModule 的導(dǎo)入語(yǔ)句,并且從 NgModuleimports 數(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)有的 AuthGuardcheckLogin() 方法中已經(jīng)有了支持 CanLoad 守衛(wèi)的基礎(chǔ)邏輯。

打開(kāi) "auth.guard.ts",從 @angular/router 中導(dǎo)入 CanLoad 接口。 把它添加到 AuthGuard 類的 implements 列表中。 然后實(shí)現(xiàn) canLoad,代碼如下:

Path:"src/app/auth/auth.guard.ts (CanLoad guard)" 。

canLoad(route: Route): boolean {
  let 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:"app-routing.module.ts (lazy admin route)" 。

{
  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)該急性加載 AppModuleHeroesModule。

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

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

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

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

  • 完全不預(yù)加載,這是默認(rèn)值。惰性加載的特性區(qū)仍然會(huì)按需加載。

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

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

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

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

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

  • CrisisCenterRoutingModule 中的路徑從 crisis-center 改為空字符串。

  • AppRoutingModule 中添加一個(gè) crisis-center 路由。

  • 設(shè)置 loadChildren 字符串來(lái)加載 CrisisCenterModule。

  • 從 "app.module.ts" 中移除所有對(duì) CrisisCenterModule 的引用。

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

  • Path:"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 {
        }

  • Path:"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 {}

  • Path:"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)用中:

Path:"src/app/app-routing.module.ts (preload all)" 。

    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)?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ú)依賴CanActivate 守衛(wèi)。

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

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

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

AppRoutingModulecrisis-center 路由中設(shè)置 data.preload 標(biāo)志。

Path:"src/app/app-routing.module.ts (route data preload)" 。

{
  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":

Path:"src/app/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 && route.data['preload']) {
      // 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. 要加載的路由。

  1. 一個(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 中。

  1. PreloadAllModules 策略替換成對(duì) forRoot() 的調(diào)用,并且傳入這個(gè) SelectivePreloadingStrategyService。

  1. SelectivePreloadingStrategyService 策略添加到 AppRoutingModuleproviders 數(shù)組中,以便它可以注入到應(yīng)用中的任何地方。

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

導(dǎo)入 SelectivePreloadingStrategyService(它是一個(gè)服務(wù))。

把它注入到儀表盤(pán)的構(gòu)造函數(shù)中。

修改模板來(lái)顯示這個(gè)策略服務(wù)的 preloadedModules 數(shù)組。

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

Path:"src/app/admin/admin-dashboard/admin-dashboard.component.ts (preloaded modules)" 。

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" 指向了 HeroListComponentHeroDetailComponent 組件。 如果有這樣一個(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" 文件中把老的路由重定向到新的路由。

Path:"src/app/heroes/heroes-routing.module.ts (heroes redirects)" 。

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 { }

注意,這里有兩種類型的重定向。第一種是不帶參數(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)?Router 在每一層的路由配置中只會(huì)處理一次重定向。這樣可以防止出現(xiàn)無(wú)限循環(huán)的重定向。

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

Path:"src/app/app-routing.module.ts (superheroes redirect)" 。

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

Path:"src/app/app.component.html (superheroes active routerLink))" 。

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

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

Path:"src/app/heroes/hero-detail/hero-detail.component.ts (goToHeroes)" 。

gotoHeroes(hero: Hero) {
  let 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)窗口中查看最終的路由配置。

Path:"src/app/app.module.ts (inspect the router config)" 。

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) 下載范例 的最終代碼。

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

掃描二維碼

下載編程獅App

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

編程獅公眾號(hào)