模块与懒加载 #
一、模块概述 #
Angular模块(NgModule)用于组织应用结构,管理组件、指令、管道和服务。
二、NgModule #
2.1 模块结构 #
typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { UserListComponent } from './user-list.component';
import { UserDetailComponent } from './user-detail.component';
import { UserService } from './user.service';
@NgModule({
declarations: [
UserListComponent,
UserDetailComponent
],
imports: [
CommonModule,
FormsModule,
RouterModule
],
exports: [
UserListComponent
],
providers: [
UserService
]
})
export class UserModule { }
2.2 模块配置项 #
| 配置项 | 说明 |
|---|---|
declarations |
声明组件、指令、管道 |
imports |
导入其他模块 |
exports |
导出供其他模块使用 |
providers |
注册服务 |
bootstrap |
根组件 |
2.3 常用模块 #
| 模块 | 说明 |
|---|---|
BrowserModule |
浏览器支持 |
CommonModule |
通用指令和管道 |
FormsModule |
模板驱动表单 |
ReactiveFormsModule |
响应式表单 |
HttpClientModule |
HTTP客户端 |
RouterModule |
路由 |
三、独立组件 #
3.1 独立组件(Standalone) #
typescript
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-user-card',
standalone: true,
imports: [CommonModule, FormsModule],
template: `
<div class="card">
<h3>{{ user.name }}</h3>
<input [(ngModel)]="user.email" />
</div>
`
})
export class UserCardComponent {
user = { name: 'John', email: 'john@example.com' };
}
3.2 引导独立应用 #
typescript
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
bootstrapApplication(AppComponent, appConfig)
.catch(err => console.error(err));
3.3 应用配置 #
typescript
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient()
]
};
四、懒加载 #
4.1 路由懒加载模块 #
typescript
import { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'users',
loadChildren: () => import('./users/users.module')
.then(m => m.UsersModule)
},
{
path: 'admin',
loadChildren: () => import('./admin/admin.module')
.then(m => m.AdminModule)
}
];
4.2 懒加载模块路由 #
typescript
@NgModule({
imports: [
RouterModule.forChild([
{ path: '', component: UserListComponent },
{ path: ':id', component: UserDetailComponent }
])
],
declarations: [UserListComponent, UserDetailComponent]
})
export class UsersModule { }
4.3 懒加载独立组件 #
typescript
export const routes: Routes = [
{
path: 'users',
loadComponent: () => import('./users/user-list.component')
.then(c => c.UserListComponent)
},
{
path: 'users/:id',
loadComponent: () => import('./users/user-detail.component')
.then(c => c.UserDetailComponent)
}
];
五、预加载策略 #
5.1 预加载所有模块 #
typescript
import { provideRouter, PreloadAllModules } from '@angular/router';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes, PreloadAllModules)
]
};
5.2 自定义预加载策略 #
typescript
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class SelectivePreloadingStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
if (route.data?.['preload']) {
return load();
}
return of(null);
}
}
// 配置路由
export const routes: Routes = [
{
path: 'users',
loadChildren: () => import('./users/users.module').then(m => m.UsersModule),
data: { preload: true }
},
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
data: { preload: false }
}
];
// 应用配置
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes, SelectivePreloadingStrategy)
]
};
5.3 按需预加载 #
typescript
@Injectable({ providedIn: 'root' })
export class OnDemandPreloadService {
private preloadSubject = new Subject<string>();
preload$ = this.preloadSubject.asObservable();
startPreload(modulePath: string) {
this.preloadSubject.next(modulePath);
}
}
@Injectable({ providedIn: 'root' })
export class OnDemandPreloadingStrategy implements PreloadingStrategy {
constructor(private preloadService: OnDemandPreloadService) {}
preload(route: Route, load: () => Observable<any>): Observable<any> {
return this.preloadService.preload$.pipe(
filter(path => path === route.path),
first(),
switchMap(() => load())
);
}
}
六、模块组织 #
6.1 功能模块 #
text
src/app/
├── core/ # 核心模块
│ ├── services/
│ ├── guards/
│ ├── interceptors/
│ └── core.module.ts
├── shared/ # 共享模块
│ ├── components/
│ ├── directives/
│ ├── pipes/
│ └── shared.module.ts
├── features/ # 功能模块
│ ├── user/
│ │ ├── components/
│ │ ├── services/
│ │ └── user.module.ts
│ └── product/
│ ├── components/
│ ├── services/
│ └── product.module.ts
└── app.module.ts
6.2 核心模块 #
typescript
@NgModule({
imports: [CommonModule, HttpClientModule],
providers: [
AuthService,
ApiService,
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
})
export class CoreModule {
constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
if (parentModule) {
throw new Error('CoreModule只能被AppModule导入');
}
}
}
6.3 共享模块 #
typescript
@NgModule({
imports: [CommonModule, FormsModule, ReactiveFormsModule],
declarations: [
ButtonComponent,
InputComponent,
HighlightDirective,
TruncatePipe
],
exports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
ButtonComponent,
InputComponent,
HighlightDirective,
TruncatePipe
]
})
export class SharedModule { }
七、模块最佳实践 #
7.1 模块划分原则 #
- 核心模块:全局服务、单例服务
- 共享模块:可复用组件、指令、管道
- 功能模块:按业务功能划分
7.2 避免循环依赖 #
typescript
// 错误:模块A导入模块B,模块B导入模块A
// 正确:提取共享部分到共享模块
7.3 服务作用域 #
typescript
// 全局单例
@Injectable({ providedIn: 'root' })
// 模块级单例
@NgModule({
providers: [FeatureService]
})
// 组件级实例
@Component({
providers: [ComponentService]
})
八、性能优化 #
8.1 懒加载策略 #
typescript
// 按需加载
{
path: 'feature',
loadChildren: () => import('./feature/feature.module')
.then(m => m.FeatureModule)
}
8.2 预加载关键模块 #
typescript
{
path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.module')
.then(m => m.DashboardModule),
data: { preload: true }
}
8.3 减少模块大小 #
typescript
// 按需导入
import { CommonModule } from '@angular/common';
// 避免导入整个模块
// import { CommonModule } from '@angular/common';
// 改为只导入需要的
九、总结 #
| 概念 | 说明 |
|---|---|
NgModule |
模块定义 |
declarations |
声明组件、指令、管道 |
imports |
导入模块 |
exports |
导出模块内容 |
providers |
注册服务 |
| 懒加载 | 按需加载模块 |
| 预加载 | 提前加载模块 |
| 独立组件 | 无需模块的组件 |
下一步:Angular样式指南
最后更新:2026-03-26