Angular样式指南 #
一、命名规范 #
1.1 文件命名 #
| 类型 | 格式 | 示例 |
|---|---|---|
| 组件 | feature.component.ts | user-list.component.ts |
| 服务 | feature.service.ts | user.service.ts |
| 模块 | feature.module.ts | user.module.ts |
| 指令 | feature.directive.ts | highlight.directive.ts |
| 管道 | feature.pipe.ts | truncate.pipe.ts |
| 守卫 | feature.guard.ts | auth.guard.ts |
| 模型 | feature.model.ts | user.model.ts |
| 接口 | feature.interface.ts | user.interface.ts |
1.2 组件命名 #
typescript
// 推荐
@Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html'
})
export class UserListComponent { }
// 不推荐
@Component({
selector: 'userList',
templateUrl: './userlist.html'
})
export class userList { }
1.3 服务命名 #
typescript
// 推荐
@Injectable({ providedIn: 'root' })
export class UserService { }
// 不推荐
@Injectable()
export class UserSvc { }
1.4 选择器命名 #
typescript
// 推荐:使用kebab-case
selector: 'app-user-card'
selector: 'app-user-list-item'
// 不推荐
selector: 'appUserCard'
selector: 'UserCard'
二、组件规范 #
2.1 组件结构 #
typescript
@Component({
selector: 'app-user-card',
standalone: true,
imports: [CommonModule],
templateUrl: './user-card.component.html',
styleUrl: './user-card.component.css',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserCardComponent implements OnInit, OnDestroy {
@Input() user: User;
@Output() selected = new EventEmitter<User>();
private destroy$ = new Subject<void>();
constructor(private userService: UserService) {}
ngOnInit(): void {}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
onSelect(): void {
this.selected.emit(this.user);
}
}
2.2 成员排序 #
typescript
export class ExampleComponent {
// 1. 输入属性
@Input() user: User;
@Input() isActive = false;
// 2. 输出属性
@Output() selected = new EventEmitter<User>();
// 3. 公共属性
isLoading = false;
users: User[] = [];
// 4. 私有属性
private subscription: Subscription;
// 5. 构造函数
constructor(private userService: UserService) {}
// 6. 生命周期钩子
ngOnInit(): void {}
ngOnDestroy(): void {}
// 7. 公共方法
loadUsers(): void {}
// 8. 私有方法
private handleError(error: Error): void {}
}
2.3 使用OnPush #
typescript
@Component({
selector: 'app-user-list',
template: '...',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserListComponent {
@Input() users: User[];
}
三、服务规范 #
3.1 服务结构 #
typescript
@Injectable({ providedIn: 'root' })
export class UserService {
private readonly apiUrl = '/api/users';
private usersSubject = new BehaviorSubject<User[]>([]);
users$ = this.usersSubject.asObservable();
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]> {
return this.http.get<User[]>(this.apiUrl);
}
getUser(id: number): Observable<User> {
return this.http.get<User>(`${this.apiUrl}/${id}`);
}
createUser(user: User): Observable<User> {
return this.http.post<User>(this.apiUrl, user);
}
}
3.2 单一职责 #
typescript
// 推荐:职责单一
@Injectable({ providedIn: 'root' })
export class UserService { }
@Injectable({ providedIn: 'root' })
export class AuthService { }
// 不推荐:职责过多
@Injectable({ providedIn: 'root' })
export class AppService {
// 用户、认证、产品、订单...
}
四、模板规范 #
4.1 模板结构 #
html
<!-- 推荐 -->
<div class="user-card">
<h3 class="user-name">{{ user.name }}</h3>
<p class="user-email">{{ user.email }}</p>
<button
class="btn btn-primary"
(click)="onSelect()"
[disabled]="isLoading">
选择
</button>
</div>
<!-- 不推荐 -->
<div class="user-card"><h3 class="user-name">{{user.name}}</h3><p class="user-email">{{user.email}}</p><button class="btn btn-primary"(click)="onSelect()"[disabled]="isLoading">选择</button></div>
4.2 属性顺序 #
html
<input
type="text"
id="name"
name="name"
class="form-control"
[(ngModel)]="user.name"
required
minlength="2"
#nameInput="ngModel"
/>
4.3 使用新控制流语法 #
html
<!-- Angular 17+ 推荐 -->
@if (users.length > 0) {
<ul>
@for (user of users; track user.id) {
<li>{{ user.name }}</li>
}
</ul>
} @else {
<p>暂无用户</p>
}
<!-- 传统语法 -->
<div *ngIf="users.length > 0; else empty">
<ul>
<li *ngFor="let user of users; trackBy: trackById">
{{ user.name }}
</li>
</ul>
</div>
<ng-template #empty>
<p>暂无用户</p>
</ng-template>
五、样式规范 #
5.1 组件样式 #
typescript
@Component({
selector: 'app-user-card',
template: '...',
styles: [`
.user-card {
padding: 16px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.user-name {
font-size: 18px;
font-weight: bold;
}
.user-email {
color: #666;
}
`]
})
5.2 使用SCSS #
scss
// variables.scss
$primary-color: #007bff;
$border-radius: 4px;
// user-card.component.scss
@import 'variables';
.user-card {
padding: 16px;
border-radius: $border-radius;
.user-name {
color: $primary-color;
}
}
六、项目结构 #
6.1 推荐结构 #
text
src/app/
├── core/ # 核心模块
│ ├── services/
│ │ ├── auth.service.ts
│ │ └── api.service.ts
│ ├── guards/
│ │ └── auth.guard.ts
│ ├── interceptors/
│ │ └── auth.interceptor.ts
│ └── models/
│ └── user.model.ts
├── shared/ # 共享模块
│ ├── components/
│ │ ├── button/
│ │ └── input/
│ ├── directives/
│ │ └── highlight/
│ └── pipes/
│ └── truncate/
├── features/ # 功能模块
│ ├── user/
│ │ ├── components/
│ │ ├── services/
│ │ └── user.routes.ts
│ └── product/
│ ├── components/
│ ├── services/
│ └── product.routes.ts
├── app.component.ts
├── app.config.ts
└── app.routes.ts
6.2 功能模块结构 #
text
features/user/
├── components/
│ ├── user-list/
│ │ ├── user-list.component.ts
│ │ ├── user-list.component.html
│ │ └── user-list.component.scss
│ └── user-detail/
│ ├── user-detail.component.ts
│ ├── user-detail.component.html
│ └── user-detail.component.scss
├── services/
│ └── user.service.ts
├── models/
│ └── user.model.ts
└── user.routes.ts
七、编码规范 #
7.1 使用const #
typescript
// 推荐
const MAX_USERS = 100;
const API_URL = '/api/users';
// 不推荐
var maxUsers = 100;
let apiUrl = '/api/users';
7.2 使用接口 #
typescript
// 推荐
interface User {
id: number;
name: string;
email: string;
}
// 不推荐
type User = {
id: number;
name: string;
email: string;
};
7.3 使用可选链 #
typescript
// 推荐
const name = user?.profile?.name;
// 不推荐
const name = user && user.profile && user.profile.name;
7.4 使用空值合并 #
typescript
// 推荐
const name = user?.name ?? 'Unknown';
// 不推荐
const name = user?.name ? user.name : 'Unknown';
八、性能规范 #
8.1 使用trackBy #
typescript
@Component({
template: `
<li *ngFor="let user of users; trackBy: trackById">
{{ user.name }}
</li>
`
})
export class UserListComponent {
trackById(index: number, user: User): number {
return user.id;
}
}
8.2 使用OnPush #
typescript
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
8.3 避免内存泄漏 #
typescript
export class ExampleComponent implements OnInit, OnDestroy {
private destroy$ = new Subject<void>();
ngOnInit() {
this.service.getData()
.pipe(takeUntil(this.destroy$))
.subscribe();
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
九、总结 #
| 规范 | 说明 |
|---|---|
| 命名规范 | 使用一致的命名约定 |
| 组件规范 | 单一职责、OnPush |
| 服务规范 | providedIn: ‘root’ |
| 模板规范 | 清晰的结构 |
| 样式规范 | 组件封装样式 |
| 项目结构 | 按功能模块组织 |
下一步:性能优化
最后更新:2026-03-26