NgModule 是以 @NgModule 裝飾器標記的類別。這個裝飾器接受的中繼資料(metadata)會告訴 Angular 如何編譯元件範本,以及如何設定依賴注入。
import {NgModule} from '@angular/core';
@NgModule({
// Metadata goes here
})
export class CustomMenuModule {}
NgModule 有兩項主要職責:
- 宣告屬於該 NgModule 的元件、指令與管道
- 將提供者加入注入器,供匯入該 NgModule 的元件、指令與管道使用
Declarations
@NgModule 中繼資料的 declarations 屬性,宣告屬於該 NgModule 的元件、指令與管道。
@NgModule({
/* ... */
// CustomMenu and CustomMenuItem are components.
declarations: [CustomMenu, CustomMenuItem],
})
export class CustomMenuModule {}
在上例中,CustomMenu 與 CustomMenuItem 這兩個元件屬於 CustomMenuModule。
declarations 屬性也可以接受由元件、指令與管道組成的陣列。這些陣列本身也可以再包含其他陣列。
const MENU_COMPONENTS = [CustomMenu, CustomMenuItem];
const WIDGETS = [MENU_COMPONENTS, CustomSlider];
@NgModule({
/* ... */
// This NgModule declares all of CustomMenu, CustomMenuItem,
// CustomSlider, and CustomCheckbox.
declarations: [WIDGETS, CustomCheckbox],
})
export class CustomMenuModule {}
如果 Angular 發現有元件、指令或管道被宣告在一個以上的 NgModule 中,就會回報錯誤。
任何元件、指令或管道都必須明確標記為 standalone: false,才能宣告在 NgModule 中。
@Component({
// Mark this component as `standalone: false` so that it can be declared in an NgModule.
standalone: false,
/* ... */
})
export class CustomMenu {
/* ... */
}
imports
宣告在 NgModule 中的元件,可能會依賴其他元件、指令與管道。請將這些相依性加入 @NgModule 中繼資料的 imports 屬性。
@NgModule({
/* ... */
// CustomMenu and CustomMenuItem depend on the PopupTrigger and SelectorIndicator components.
imports: [PopupTrigger, SelectionIndicator],
declarations: [CustomMenu, CustomMenuItem],
})
export class CustomMenuModule {}
imports 陣列可以接受其他 NgModule,以及獨立元件、指令與管道。
exports
NgModule 可以匯出(export)它所宣告的元件、指令與管道,讓其他元件與 NgModule 也能使用它們。
@NgModule({
imports: [PopupTrigger, SelectionIndicator],
declarations: [CustomMenu, CustomMenuItem],
// Make CustomMenu and CustomMenuItem available to
// components and NgModules that import CustomMenuModule.
exports: [CustomMenu, CustomMenuItem],
})
export class CustomMenuModule {}
不過,exports 屬性不限於宣告的內容。NgModule 也可以匯出它所匯入的任何其他元件、指令、管道與 NgModule。
@NgModule({
imports: [PopupTrigger, SelectionIndicator],
declarations: [CustomMenu, CustomMenuItem],
// Also make PopupTrigger available to any component or NgModule that imports CustomMenuModule.
exports: [CustomMenu, CustomMenuItem, PopupTrigger],
})
export class CustomMenuModule {}
NgModule providers
TIP: 有關依賴注入與提供者的資訊,請參閱依賴注入指南。
NgModule 可以為注入的相依性指定 providers。這些提供者可供下列目標使用:
- 任何匯入該 NgModule 的獨立元件、指令或管道,以及
- 任何匯入該 NgModule 的其他 NgModule 的
declarations與providers。
@NgModule({
imports: [PopupTrigger, SelectionIndicator],
declarations: [CustomMenu, CustomMenuItem],
// Provide the OverlayManager service
providers: [OverlayManager],
/* ... */
})
export class CustomMenuModule {}
@NgModule({
imports: [CustomMenuModule],
declarations: [UserProfile],
providers: [UserDataClient],
})
export class UserProfileModule {}
在上例中:
CustomMenuModule提供了OverlayManager。CustomMenu與CustomMenuItem元件可以注入OverlayManager,因為它們宣告在CustomMenuModule中。UserProfile可以注入OverlayManager,因為它的 NgModule 匯入了CustomMenuModule。UserDataClient可以注入OverlayManager,因為它的 NgModule 匯入了CustomMenuModule。
The forRoot and forChild pattern
有些 NgModule 會定義靜態的 forRoot 方法,接受一些設定並回傳一組提供者。「forRoot」這個名稱是一種慣例,表示這些提供者應該在啟動(bootstrap)時,專門加入應用程式的根部(root)。
以這種方式加入的任何提供者都會被積極載入(eagerly loaded),進而增加初始頁面載入時的 JavaScript 套件大小。
bootstrapApplication(MyApplicationRoot, {
providers: [CustomMenuModule.forRoot(/* some config */)],
});
同樣地,有些 NgModule 可能會定義靜態的 forChild,表示這些提供者應該加入應用程式階層中的元件。
@Component({
/* ... */
providers: [CustomMenuModule.forChild(/* some config */)],
})
export class UserProfile {
/* ... */
}
Bootstrapping an application
IMPORTANT: Angular 團隊建議所有新程式碼都使用 bootstrapApplication,而不是 bootstrapModule。請透過本指南了解以 @NgModule 啟動的既有應用程式。
@NgModule 裝飾器接受一個可選的 bootstrap 陣列,其中可以包含一個或多個元件。
你可以使用 platformBrowser 或 platformServer 的 bootstrapModule 方法來啟動 Angular 應用程式。執行時,這個函式會在頁面上找出 CSS 選取器與所列元件相符的元素,並在頁面上渲染這些元件。
import {platformBrowser} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
@NgModule({
declarations: [MyApplication],
bootstrap: [MyApplication],
})
export class MyApplicationModule {}
platformBrowser().bootstrapModule(MyApplicationModule);
列在 bootstrap 中的元件也必須在 NgModule 的 declarations 中宣告。
當你從 NgModule 啟動應用程式時,該模組收集到的 providers,以及它所有 imports 的 providers,都會被積極載入,並可供整個應用程式注入使用。