angular-module-design
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAngular Module Design
Angular 模块设计
Overview
概述
Architect scalable Angular applications using feature modules, lazy loading, services, and RxJS for reactive programming patterns.
使用特性模块、懒加载、服务和RxJS构建可扩展的Angular应用,实现响应式编程模式。
When to Use
适用场景
- Large Angular applications
- Feature-based organization
- Lazy loading optimization
- Dependency injection patterns
- Reactive state management
- 大型Angular应用
- 基于特性的组织方式
- 懒加载优化
- 依赖注入模式
- 响应式状态管理
Implementation Examples
实现示例
1. Feature Module Structure
1. 特性模块结构
typescript
// users.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { UsersRoutingModule } from './users-routing.module';
import { UsersListComponent } from './components/users-list/users-list.component';
import { UserDetailComponent } from './components/user-detail/user-detail.component';
import { UsersService } from './services/users.service';
@NgModule({
declarations: [UsersListComponent, UserDetailComponent],
imports: [CommonModule, ReactiveFormsModule, UsersRoutingModule],
providers: [UsersService]
})
export class UsersModule {}typescript
// users.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule } from '@angular/forms';
import { UsersRoutingModule } from './users-routing.module';
import { UsersListComponent } from './components/users-list/users-list.component';
import { UserDetailComponent } from './components/user-detail/user-detail.component';
import { UsersService } from './services/users.service';
@NgModule({
declarations: [UsersListComponent, UserDetailComponent],
imports: [CommonModule, ReactiveFormsModule, UsersRoutingModule],
providers: [UsersService]
})
export class UsersModule {}2. Lazy Loading Routes
2. 懒加载路由
typescript
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './components/dashboard/dashboard.component';
const routes: Routes = [
{ path: '', component: DashboardComponent },
{
path: 'users',
loadChildren: () => import('./features/users/users.module')
.then(m => m.UsersModule)
},
{
path: 'products',
loadChildren: () => import('./features/products/products.module')
.then(m => m.ProductsModule)
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}typescript
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './components/dashboard/dashboard.component';
const routes: Routes = [
{ path: '', component: DashboardComponent },
{
path: 'users',
loadChildren: () => import('./features/users/users.module')
.then(m => m.UsersModule)
},
{
path: 'products',
loadChildren: () => import('./features/products/products.module')
.then(m => m.ProductsModule)
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}3. Service with RxJS
3. 结合RxJS的服务
typescript
// users.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, throwError } from 'rxjs';
import { map, catchError, tap } from 'rxjs/operators';
interface User {
id: number;
name: string;
email: string;
}
@Injectable({ providedIn: 'root' })
export class UsersService {
private usersSubject = new BehaviorSubject<User[]>([]);
public users$ = this.usersSubject.asObservable();
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users').pipe(
tap(users => this.usersSubject.next(users)),
catchError(error => {
console.error('Error fetching users:', error);
return throwError(() => new Error('Failed to load users'));
})
);
}
getUserById(id: number): Observable<User> {
return this.http.get<User>(`/api/users/${id}`);
}
createUser(user: Omit<User, 'id'>): Observable<User> {
return this.http.post<User>('/api/users', user).pipe(
tap(newUser => {
const currentUsers = this.usersSubject.value;
this.usersSubject.next([...currentUsers, newUser]);
})
);
}
updateUser(id: number, user: User): Observable<User> {
return this.http.put<User>(`/api/users/${id}`, user).pipe(
tap(updatedUser => {
const currentUsers = this.usersSubject.value;
const index = currentUsers.findIndex(u => u.id === id);
if (index !== -1) {
currentUsers[index] = updatedUser;
this.usersSubject.next([...currentUsers]);
}
})
);
}
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`/api/users/${id}`).pipe(
tap(() => {
const currentUsers = this.usersSubject.value;
this.usersSubject.next(currentUsers.filter(u => u.id !== id));
})
);
}
}typescript
// users.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, throwError } from 'rxjs';
import { map, catchError, tap } from 'rxjs/operators';
interface User {
id: number;
name: string;
email: string;
}
@Injectable({ providedIn: 'root' })
export class UsersService {
private usersSubject = new BehaviorSubject<User[]>([]);
public users$ = this.usersSubject.asObservable();
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>('/api/users').pipe(
tap(users => this.usersSubject.next(users)),
catchError(error => {
console.error('Error fetching users:', error);
return throwError(() => new Error('Failed to load users'));
})
);
}
getUserById(id: number): Observable<User> {
return this.http.get<User>(`/api/users/${id}`);
}
createUser(user: Omit<User, 'id'>): Observable<User> {
return this.http.post<User>('/api/users', user).pipe(
tap(newUser => {
const currentUsers = this.usersSubject.value;
this.usersSubject.next([...currentUsers, newUser]);
})
);
}
updateUser(id: number, user: User): Observable<User> {
return this.http.put<User>(`/api/users/${id}`, user).pipe(
tap(updatedUser => {
const currentUsers = this.usersSubject.value;
const index = currentUsers.findIndex(u => u.id === id);
if (index !== -1) {
currentUsers[index] = updatedUser;
this.usersSubject.next([...currentUsers]);
}
})
);
}
deleteUser(id: number): Observable<void> {
return this.http.delete<void>(`/api/users/${id}`).pipe(
tap(() => {
const currentUsers = this.usersSubject.value;
this.usersSubject.next(currentUsers.filter(u => u.id !== id));
})
);
}
}4. Smart and Presentational Components
4. 智能组件与展示组件
typescript
// users-list.component.ts (Smart)
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { UsersService } from '../../services/users.service';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-users-list',
template: `
<div>
<h2>Users</h2>
<button (click)="addUser()">Add User</button>
<app-user-item
*ngFor="let user of users$ | async"
[user]="user"
(delete)="deleteUser($event)"
></app-user-item>
</div>
`
})
export class UsersListComponent implements OnInit {
users$: Observable<User[]>;
constructor(private usersService: UsersService) {
this.users$ = this.usersService.users$;
}
ngOnInit(): void {
this.usersService.getUsers().subscribe();
}
addUser(): void {
// Navigation or modal logic
}
deleteUser(id: number): void {
this.usersService.deleteUser(id).subscribe();
}
}
// user-item.component.ts (Presentational)
import { Component, Input, Output, EventEmitter } from '@angular/core';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-user-item',
template: `
<div class="user-item">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<button (click)="onDelete()">Delete</button>
</div>
`,
styleUrls: ['./user-item.component.css']
})
export class UserItemComponent {
@Input() user!: User;
@Output() delete = new EventEmitter<number>();
onDelete(): void {
this.delete.emit(this.user.id);
}
}typescript
// users-list.component.ts (Smart)
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { UsersService } from '../../services/users.service';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-users-list',
template: `
<div>
<h2>Users</h2>
<button (click)="addUser()">Add User</button>
<app-user-item
*ngFor="let user of users$ | async"
[user]="user"
(delete)="deleteUser($event)"
></app-user-item>
</div>
`
})
export class UsersListComponent implements OnInit {
users$: Observable<User[]>;
constructor(private usersService: UsersService) {
this.users$ = this.usersService.users$;
}
ngOnInit(): void {
this.usersService.getUsers().subscribe();
}
addUser(): void {
// Navigation or modal logic
}
deleteUser(id: number): void {
this.usersService.deleteUser(id).subscribe();
}
}
// user-item.component.ts (Presentational)
import { Component, Input, Output, EventEmitter } from '@angular/core';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-user-item',
template: `
<div class="user-item">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
<button (click)="onDelete()">Delete</button>
</div>
`,
styleUrls: ['./user-item.component.css']
})
export class UserItemComponent {
@Input() user!: User;
@Output() delete = new EventEmitter<number>();
onDelete(): void {
this.delete.emit(this.user.id);
}
}5. Dependency Injection and Providers
5. 依赖注入与提供者
typescript
// config.service.ts
import { Injectable } from '@angular/core';
interface AppConfig {
apiUrl: string;
environment: string;
}
@Injectable({ providedIn: 'root' })
export class ConfigService {
private config: AppConfig = {
apiUrl: 'https://api.example.com',
environment: 'production'
};
get(key: keyof AppConfig): any {
return this.config[key];
}
}
// app.module.ts with providers
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { ConfigService } from './services/config.service';
import { AuthInterceptor } from './interceptors/auth.interceptor';
@NgModule({
imports: [BrowserModule, HttpClientModule],
providers: [
ConfigService,
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
})
export class AppModule {}typescript
// config.service.ts
import { Injectable } from '@angular/core';
interface AppConfig {
apiUrl: string;
environment: string;
}
@Injectable({ providedIn: 'root' })
export class ConfigService {
private config: AppConfig = {
apiUrl: 'https://api.example.com',
environment: 'production'
};
get(key: keyof AppConfig): any {
return this.config[key];
}
}
// app.module.ts with providers
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { ConfigService } from './services/config.service';
import { AuthInterceptor } from './interceptors/auth.interceptor';
@NgModule({
imports: [BrowserModule, HttpClientModule],
providers: [
ConfigService,
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
})
export class AppModule {}Best Practices
最佳实践
- Organize by feature modules
- Use lazy loading for large features
- Implement smart/presentational component pattern
- Use services for data and business logic
- Leverage RxJS for reactive patterns
- Use dependency injection for loose coupling
- Implement HTTP interceptors for global handling
- Use typed services and models
- 按特性模块组织代码
- 对大型特性使用懒加载
- 实现智能/展示组件模式
- 使用服务处理数据和业务逻辑
- 利用RxJS实现响应式模式
- 使用依赖注入实现松耦合
- 实现HTTP拦截器进行全局处理
- 使用类型化服务和模型