默認(rèn)情況下,NgModule
都是急性加載的,也就是說它會(huì)在應(yīng)用加載時(shí)盡快加載,所有模塊都是如此,無論是否立即要用。對(duì)于帶有很多路由的大型應(yīng)用,考慮使用惰性加載 —— 一種按需加載 NgModule
的模式。惰性加載可以減小初始包的尺寸,從而減少加載時(shí)間。
本節(jié)會(huì)介紹配置惰性加載路由的基本過程。 想要一個(gè)分步的范例,參見本頁(yè)的分步設(shè)置部分。
要惰性加載 Angular 模塊,請(qǐng)?jiān)?AppRoutingModule routes
中使用 loadchildren
代替 component
進(jìn)行配置,代碼如下。
//AppRoutingModule (excerpt)
const routes: Routes = [
{
path: 'items',
loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
}
];
在惰性加載模塊的路由模塊中,添加一個(gè)指向該組件的路由。
//Routing module for lazy loaded module (excerpt)
const routes: Routes = [
{
path: '',
component: ItemsComponent
}
];
還要確保從 AppModule
中移除了 ItemsModule
。
建立惰性加載的特性模塊有兩個(gè)主要步驟:
--route
標(biāo)志,用 CLI 創(chuàng)建特性模塊。
如果你還沒有應(yīng)用,可以遵循下面的步驟使用 CLI 創(chuàng)建一個(gè)。如果已經(jīng)有了,可以直接跳到 配置路由部分。 輸入下列命令,其中的 customer-app
表示你的應(yīng)用名稱:
ng new customer-app --routing
這會(huì)創(chuàng)建一個(gè)名叫 "customer-app" 的應(yīng)用,而 --routing
標(biāo)識(shí)生成了一個(gè)名叫 "app-routing.module.ts" 的文件,它是你建立惰性加載的特性模塊時(shí)所必須的。 輸入命令 cd customer-app
進(jìn)入該項(xiàng)目。
注:
- --routing 選項(xiàng)需要 Angular/CLI 8.1 或更高版本。
接下來,你將需要一個(gè)包含路由的目標(biāo)組件的特性模塊。 要?jiǎng)?chuàng)建它,在終端中輸入如下命令,其中 customers
是特性模塊的名稱。加載 customers
特性模塊的路徑也是 customers
,因?yàn)樗峭ㄟ^ --route
選項(xiàng)指定的:
ng generate module customers --route customers --module app.module
這將創(chuàng)建一個(gè) "customers" 文件夾,在其 "customers.module.ts" 文件中定義了新的可惰性加載模塊 CustomersModule
。該命令會(huì)自動(dòng)在新特性模塊中聲明 CustomersComponent
。
因?yàn)檫@個(gè)新模塊想要惰性加載,所以該命令不會(huì)在應(yīng)用的根模塊 "app.module.ts" 中添加對(duì)新特性模塊的引用。 相反,它將聲明的路由 customers
添加到以 --module
選項(xiàng)指定的模塊中聲明的 routes
數(shù)組中。
Path:"src/app/app-routing.module.ts" 。
const routes: Routes = [
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
}
];
惰性加載語法使用 loadChildren
,其后是一個(gè)使用瀏覽器內(nèi)置的 import('...')
語法進(jìn)行動(dòng)態(tài)導(dǎo)入的函數(shù)。 其導(dǎo)入路徑是到當(dāng)前模塊的相對(duì)路徑。
使用同樣的命令創(chuàng)建第二個(gè)帶路由的惰性加載特性模塊及其樁組件。
ng generate module orders --route orders --module app.module
這將創(chuàng)建一個(gè)名為 "orders" 的新文件夾,其中包含 OrdersModule
和 OrdersRoutingModule
以及新的 OrdersComponent
源文件。 使用 --route
選項(xiàng)指定的 orders
路由,用惰性加載語法添加到了 "app-routing.module.ts" 文件內(nèi)的 routes
數(shù)組中。
Path:"src/app/app-routing.module.ts" 。
const routes: Routes = [
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
},
{
path: 'orders',
loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule)
}
];
雖然你也可以在地址欄中輸入 URL,不過導(dǎo)航 UI 會(huì)更好用,也更常見。 把 "app.component.html" 中的占位腳本替換成一個(gè)自定義的導(dǎo)航,以便你在瀏覽器中能輕松地在模塊之間導(dǎo)航。
Path:"src/app/app.component.html" 。
<h1>
{{title}}
</h1>
<button routerLink="/customers">Customers</button>
<button routerLink="/orders">Orders</button>
<button routerLink="">Home</button>
<router-outlet></router-outlet>
要想在瀏覽器中看到你的應(yīng)用,就在終端窗口中輸入下列命令:
ng serve
然后,跳轉(zhuǎn)到 "localhost:4200",這時(shí)你應(yīng)該看到 "customer-app" 和三個(gè)按鈕。
這些按鈕生效了,因?yàn)?CLI 會(huì)自動(dòng)將特性模塊的路由添加到 "app.module.ts" 中的 routes
數(shù)組中。
CLI 會(huì)將每個(gè)特性模塊自動(dòng)添加到應(yīng)用級(jí)的路由映射表中。 通過添加默認(rèn)路由來最終完成這些步驟。 在 "app-routing.module.ts" 文件中,使用如下命令更新 routes
數(shù)組:
Path:"src/app/app-routing.module.ts" 。
const routes: Routes = [
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then(m => m.CustomersModule)
},
{
path: 'orders',
loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule)
},
{
path: '',
redirectTo: '',
pathMatch: 'full'
}
];
前兩個(gè)路徑是到 CustomersModule
和 OrdersModule
的路由。 最后一個(gè)條目則定義了默認(rèn)路由。空路徑匹配所有不匹配先前路徑的內(nèi)容。
接下來,仔細(xì)看看 "customers.module.ts" 文件。如果你使用的是 CLI,并按照此頁(yè)面中的步驟進(jìn)行操作,則無需在此處執(zhí)行任何操作。
Path:"src/app/customers/customers.module.ts" 。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CustomersRoutingModule } from './customers-routing.module';
import { CustomersComponent } from './customers.component';
@NgModule({
imports: [
CommonModule,
CustomersRoutingModule
],
declarations: [CustomersComponent]
})
export class CustomersModule { }
"customers.module.ts" 文件導(dǎo)入了 "customers-routing.module.ts" 和 "customers.component.ts" 文件。@NgModule
的 imports
數(shù)組中列出了 CustomersRoutingModule
,讓 CustomersModule
可以訪問它自己的路由模塊。CustomersComponent
位于 declarations
數(shù)組中,這意味著 CustomersComponent
屬于 CustomersModule
。
然后,"app-routing.module.ts" 會(huì)使用 JavaScript 的動(dòng)態(tài)導(dǎo)入功能來導(dǎo)入特性模塊 "customers.module.ts"。
專屬于特性模塊的路由定義文件 "customers-routing.module.ts" 將導(dǎo)入在 "customers.component.ts" 文件中定義的自有特性組件,以及其它 JavaScript 導(dǎo)入語句。然后將空路徑映射到 CustomersComponent
。
Path:"src/app/customers/customers-routing.module.ts" 。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CustomersComponent } from './customers.component';
const routes: Routes = [
{
path: '',
component: CustomersComponent
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class CustomersRoutingModule { }
這里的 path
設(shè)置為空字符串,因?yàn)?AppRoutingModule
中的路徑已經(jīng)設(shè)置為 customers
,因此,CustomersRoutingModule
中的此路由已經(jīng)位于 customers
這個(gè)上下文中。此路由模塊中的每個(gè)路由都是其子路由。
另一個(gè)特性模塊中路由模塊的配置也類似。
Path:"src/app/orders/orders-routing.module.ts (excerpt)" 。
import { OrdersComponent } from './orders.component';
const routes: Routes = [
{
path: '',
component: OrdersComponent
}
];
你可以使用 Chrome 開發(fā)者工具來確認(rèn)一下這些模塊真的是惰性加載的。 在 Chrome 中,按 Cmd+Option+i(Mac)或 Ctrl+Shift+j(PC),并選中 Network 頁(yè)標(biāo)簽。
點(diǎn)擊 Orders
或 Customers
按鈕。如果你看到某個(gè) chunk
文件出現(xiàn)了,就表示一切就緒,特性模塊被惰性加載成功了。Orders
和 Customers
都應(yīng)該出現(xiàn)一次 chunk
,并且它們各自只應(yīng)該出現(xiàn)一次。
要想再次查看它或測(cè)試本項(xiàng)目后面的行為,只要點(diǎn)擊 Network 頁(yè)左上放的 清除 圖標(biāo)即可。
然后,使用 Cmd+r(Mac) 或 Ctrl+r(PC) 重新加載頁(yè)面。
你可能已經(jīng)注意到了,CLI 會(huì)把 RouterModule.forRoot(routes)
添加到 AppRoutingModule
的 imports
數(shù)組中。 這會(huì)讓 Angular 知道 AppRoutingModule
是一個(gè)路由模塊,而 forRoot()
表示這是一個(gè)根路由模塊。 它會(huì)配置你傳入的所有路由、讓你能訪問路由器指令并注冊(cè) Router
。 forRoot()
在應(yīng)用中只應(yīng)該使用一次,也就是這個(gè) AppRoutingModule
中。
CLI 還會(huì)把 RouterModule.forChild(routes)
添加到各個(gè)特性模塊中。這種方式下 Angular 就會(huì)知道這個(gè)路由列表只負(fù)責(zé)提供額外的路由并且其設(shè)計(jì)意圖是作為特性模塊使用。你可以在多個(gè)模塊中使用 forChild()
。
forRoot()
方法為路由器管理全局性的注入器配置。 forChild()
方法中沒有注入器配置,只有像 RouterOutlet
和 RouterLink
這樣的指令。 欲知詳情,參見單例服務(wù)章的 forRoot()
模式小節(jié)。
預(yù)加載通過在后臺(tái)加載部分應(yīng)用來改進(jìn)用戶體驗(yàn)。你可以預(yù)加載模塊或組件數(shù)據(jù)。
預(yù)加載模塊通過在后臺(tái)加載部分應(yīng)用來改善用戶體驗(yàn),這樣用戶在激活路由時(shí)就無需等待下載這些元素。
要啟用所有惰性加載模塊的預(yù)加載, 請(qǐng)從 Angular 的 router
導(dǎo)入 PreloadAllModules
令牌。
//AppRoutingModule (excerpt)
import { PreloadAllModules } from '@angular/router';
還是在 AppRoutingModule
中,通過 forRoot()
指定你的預(yù)加載策略。
//AppRoutingModule (excerpt)
RouterModule.forRoot(
appRoutes,
{
preloadingStrategy: PreloadAllModules
}
)
要預(yù)加載組件數(shù)據(jù),你可以使用 resolver
守衛(wèi)。解析器通過阻止頁(yè)面加載來改進(jìn)用戶體驗(yàn),直到顯示頁(yè)面時(shí)的全部必要數(shù)據(jù)都可用。
創(chuàng)建一個(gè)解析器服務(wù)。通過 CLI,生成服務(wù)的命令如下:
ng generate service
在你的服務(wù)中,導(dǎo)入下列路由器成員,實(shí)現(xiàn) Resolve
接口,并注入到 Router
服務(wù)中:
//Resolver service (excerpt)
import { Resolve } from '@angular/router';
...
export class CrisisDetailResolverService implements Resolve<> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<> {
// your logic goes here
}
}
把這個(gè)解析器導(dǎo)入此模塊的路由模塊。
//Feature module's routing module (excerpt)
import { YourResolverService } from './your-resolver.service';
在組件的 route
配置中添加一個(gè) resolve
對(duì)象。
//Feature module's routing module (excerpt)
{
path: '/your-path',
component: YourComponent,
resolve: {
crisis: YourResolverService
}
}
在此組件中,使用一個(gè) Observable
來從 ActivatedRoute
獲取數(shù)據(jù)。
//Component (excerpt)
ngOnInit() {
this.route.data
.subscribe((your-parameters) => {
// your data-specific code goes here
});
}
···
更多建議: