NgModule 模塊是Angular中一個重要的點,因為Angular的基本構造塊就是NgModule。本篇文章就來帶大家了解一下Angular中的NgModule模塊,希望對大家有所幫助!
前端(vue)入門到精通課程:進入學習
NgModule 會把相關的代碼收集到一些功能集中,形成功能單元。在使用Angular CL 命令新建一個項目的時候,會給我們生成一個根模塊,命名為 AppModule,根模塊有一個根組件AppComponent,引導這個根模塊就可以啟動應用。
Angular 應用是模塊化的,我們在開發中會根據其功能 作用 以及其特性,建立大大小小各種模塊,從而構建其成為一個應用程序,任何模塊都能包含任意數量的其它組件。【相關教程推薦:《angularjs視頻教程》】
1.@NgModule()
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
由⬆️代碼我們可以看到,NgModule 是一個帶有 @NgModule()
裝飾器的類,它接受一個元數據對象,該對象的屬性用來描述這個模塊。
點進去@NgModule()
裝飾器的類我們可以看到他有如下屬性以及官方的對其屬性的解釋。
export declare interface NgModule { providers?: Provider[];// 本模塊向全局服務中貢獻的那些服務的創建器。 這些服務能被本應用中的任何部分使用。(你也可以在組件級別指定服務提供商,這通常是首選方式。) declarations?: Array<Type<any> | any[]>;// 那些屬于本 NgModule 的組件、指令、管道 imports?: Array<Type<any> | ModuleWithProviders<{}> | any[]>;// 那些導出了本模塊中的組件模板所需的類的其它模塊 exports?: Array<Type<any> | any[]>;//那些能在其它模塊的組件模板中使用的可聲明對象的子集 entryComponents?: Array<Type<any> | any[]>; bootstrap?: Array<Type<any> | any[]>; schemas?: Array<SchemaMetadata | any[]>; }
以下是本人使用Angular后對此元數據屬性個人口語化的理解
-
providers:將本模塊所有在組件中注入的服務,在這里提前定義好,否則在此模塊中使用這個服務會有錯誤提示。
-
declaration:declaration 英文意思為聲明。在這里聲明一些模塊中要使用到的一些組件,指令,管道等。
-
imports:導入一些模塊,比如說我把所有的指令構成一個模塊 我使用其中某些指令的時候,我可以選擇導入整個指令模塊。也可以導入一些通過npm install 安裝的一些模塊導入其中,才可以使用。
-
exports:導出組件or指令管道等,以供引用此模塊的模塊可以使用此模塊的組件or 指令管道等。
-
exporyComponents:entry component 表示 angular 的入口組件,可以引導組件是一個入口組件,Angular 會在引導過程中把它加載到 DOM 中。 其它入口組件是在其它時機動態加載的。字面上的意義,但是啥時候用呢,比如,我要彈出一個組件,那么這個組件是要動態加載到DOM中了吧,這個時候就需要將這個組件xxxComponent寫上了。
-
bootstrap:這個模塊啟動的時候應該啟動的組件,上面代碼可以看到AppModule是作為根模塊的啟動組件。
-
schemas:不屬于Angular的組件或者指令的元素或者屬性都需要在這里進行聲明。
2.JavaScript 模塊 與 NgModule
JavaScript 和 Angular 都使用模塊來組織代碼,雖然它們的組織形式不同,但 Angular 的應用會同時依賴兩者。
JavaScript 模塊:
模塊是內含 JavaScript 代碼的獨立文件。要讓其中的東西可用,要寫一個導出語句
例:
export class AppComponent { ... }
在其他文件中需要使用
import { AppComponent } from './app.component';
而NgModulem模塊我們在隨筆的開頭以及介紹他的元數據,對其有一定的了解了。
NgModule 類 與 JavaScript 模塊有下列關鍵性的不同:
-
1.NgModule 只綁定了可聲明的類,這些可聲明的類只是供 Angular 編譯器用的。
-
2.NgModule 與 JavaScript 類把它所有的成員類都放在一個巨型文件中不同,只要把該模塊的類列在它的 @NgModule.declarations 列表中。
-
3.NgModule 只能導出可聲明的類。這可能是它自己擁有的也可能是從其它模塊中導入的。它不會聲明或導出任何其它類型的類。
-
4.與 JavaScript 模塊不同,NgModule 可以通過把服務提供商加到 @NgModule.providers 列表中,來用服務擴展整個應用。
相比之下我們可以看出,NgModulem模塊更靈活,擴展性強,更具優勢。
3.常用模塊
首先要知道跑起來一個項目需要引用什么基本的模塊,以下是Angular 提供的一些官方的模塊。
NgModule |
導入自 |
為何使用 |
---|---|---|
|
|
當你想要在瀏覽器中運行應用時 |
|
|
當你想要使用 |
|
|
當要構建模板驅動表單時(它包含 |
|
|
當要構建響應式表單時 |
RouterModule |
@angular/router |
要使用路由功能,并且你要用到 |
|
|
當你要和服務器對話時 |
4.特性模塊的分類
官方文檔將模塊分為五大類。
- 領域特性模塊
- 帶路由的特性模塊
- 路由模塊
- 服務特性模塊
- 可視部件特性模塊
雖然我特么當年根本不知道,但是在開發中慢慢摸索其實發現也是根據模塊的特性將模塊的分類,結果不經相同。
以下為個人在開發中對功能模塊的劃分
1).業務型模塊:整一個應用程序,根據其業務功能我們可以將程序拆分為一個個模塊,有很明確的業務特性,圍繞其業務功能的模塊。例如:用戶模塊,訂單模塊等。它有自己獨立的路由,有提供與此模塊的服務,有一個or多個組件,它惰性懶加載,不會導出or提供任何組件or指令管道,引用官方、本應用程序or第三方的功能模塊。它有明確的業務特性,不與別的模塊有耦合性。
2).組件模塊:應用程序中通常都有規范化的標準設計 ,比如說統一的table,card date 等。將這些都抽出來,做成一個個組件,在模塊中導出此組件以供其他模塊使用,這樣減少了應用程序中重復的樣式代碼等。曾經我是將所有這種可能多處要使用的封裝為組件后,統一在一個模塊中導出,后來演變為每一個組件都拆分為一個模塊。這樣也是發現如果這種通用性的組件多起來的話,假設有二三十個組件在這個UIComponent模塊中,而我因為要使用其中一兩個組件而導入這個模塊,性能是很差的,所以后來都將組件拆分為一個個模塊以供業務模塊使用,例:DateModule,InputModule..等。
3).服務模塊:提供一些通用型的服務。比如說http服務對httpClient二次包裝適用于項目,文件服務,配置服務等。
4).其他模塊:應用程序中我們會根據需要會做一些指令管道等,其就形成一個指令模塊包含應用程序中所有等指令,管道模塊包含應用程序中的所有管道。后來覺得,其實這些指令管道不需要集中起來統一導出引用。因為一個模塊并不會引用到指令模塊中超過百分之八十的指令,so 只需要把它們集中到一個pipe文件夾下,哪個模塊需要用到具體個指令or管道,直接聲明在其模塊中使用便可。
5.創建,導入特性模塊
我們將系統根據其功能 業務劃分好模塊,有利于合作開發,代碼的維護和使用。
創建特性模塊
ng g m order
ng g c order/list // 訂單模塊下新建一個list 組件
我們看最后cli給我們生成的目錄結構
order.module.ts
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ListComponent } from './list/list.component'; @NgModule({ declarations: [ListComponent],//定義list組件 exports: [ListComponent],//導出list組件 imports: [ CommonModule ] }) export class OrderModule { }
list.component.ts
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-list', templateUrl: './list.component.html', styleUrls: ['./list.component.scss'] }) export class ListComponent implements OnInit { constructor() { } ngOnInit() { } }
導入使用特性模塊
現在我們導入根模塊
app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { OrderModule } from './order/order.module'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, AppRoutingModule, OrderModule //將order模塊導入 ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
app.component.html 在跟模塊使用
<!--The content below is only a placeholder and can be replaced.--> <div style="text-align:center"> <h1> Welcome to {{ title }}! </h1> </div> <app-list></app-list> <router-outlet></router-outlet>
我們可以看到渲染了order模塊的list組件
6.惰性加載模塊
如果我們將所有的模塊都導入根模塊,那么應用在初始化加載的時候就會非常慢。這時候我們應該考慮使用惰性加載。根據需求加載相應都模塊,減少應用初始化包的大小以及減少加載的時間,提高用戶體驗性。
惰性加載的模塊特點是該模塊擁有路由模塊。so 接著上面我們創建了一個訂單模塊 我們給訂單模塊加上路由。并再創建一個user.module以及user.module模塊下的list組件。
order.module
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { OrderRoutingModule } from './order-routing.module'; import { ListComponent } from './list/list.component'; @NgModule({ declarations: [ListComponent], imports: [ CommonModule, OrderRoutingModule ] }) export class OrderModule { }
order-routing.module
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { ListComponent } from './list/list.component'; const routes: Routes = [ { path: 'list', component: ListComponent }, ]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class OrderRoutingModule { }
user模塊如此類推
接下來配置路由
AppRoutingModule在頂級路由中配置
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = [ { path: 'orders', loadChildren: './order/order.module#OrderModule' }, { path: 'orders', loadChildren: './user/user.module#UserModule' } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
我們給app.component.html新增兩個button
<!--The content below is only a placeholder and can be replaced.--> <div style="text-align:center"> <h2> Welcome to {{ title }}! </h2> </div> <button routerLink="/user/list">user</button> <button routerLink="/order/list">order</button> <router-outlet></router-outlet>
效果圖
惰性加載模塊有什么好處呢,在大型項目中往往有許多個模塊,而且大很大。如果一個模塊1m,如果我們在瀏覽器輸入地址打開這個應用,瞬間要加載100m 是非常慢的,而且我們并非要是用到著這100個模塊。將系統業務拆分為各個模塊,劃分好界限。按需加載,我點擊了user 我加載user 模塊我出現user 列表,對user進行操作。當我需要使用時才加載極大的減少了頁面初始加載的時間以及減少了資源的消耗。
7.共享模塊
共享模塊顧名思義,就是共享于所有的模塊中。首先得定義好這個模塊的具體功能特性,比如指令、管道和組件等分別封裝成一個個模塊,哪些業務模塊需要使用到其里面的功能變導入其模塊中便可。簡單的比如,本系統的input 都是統一樣式的,我們可以制作一個input 模塊 然后在其他模塊直接導入使用。這極大的規范了系統的統一性和降低了以后的維護成本。