name: angular-development description: Angular开发模式,包括模块、组件、服务、依赖注入、信号和企业架构。 allowed-tools: Read, Write, Edit, Bash, Glob, Grep
Angular开发技能
为使用现代模式和最佳实践构建企业级Angular应用程序提供专家协助。
能力
- 使用独立API创建Angular组件
- 通过依赖注入实现服务
- 配置支持懒加载的路由
- 构建响应式表单和模板驱动表单
- 使用Angular信号实现响应式编程
- 设置企业级架构模式
使用场景
在以下情况下调用此技能:
- 构建Angular应用程序
- 创建模块化架构
- 实现表单和验证
- 设置Angular路由
- 配置依赖注入
输入参数
| 参数 | 类型 | 是否必需 | 描述 |
|---|---|---|---|
| componentName | 字符串 | 是 | 组件名称 |
| standalone | 布尔值 | 否 | 使用独立组件(默认:true) |
| features | 数组 | 否 | 路由、表单、http、信号 |
| style | 字符串 | 否 | css、scss、less |
配置示例
{
"componentName": "UserProfile",
"standalone": true,
"features": ["signals", "forms"],
"style": "scss"
}
组件模式
使用信号的独立组件
// components/user-profile.component.ts
import { Component, signal, computed, input, output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
interface User {
id: string;
name: string;
email: string;
}
@Component({
selector: 'app-user-profile',
standalone: true,
imports: [CommonModule, FormsModule],
template: `
<div class="user-profile">
<div class="avatar">
{{ initials() }}
</div>
@if (isEditing()) {
<input [(ngModel)]="editedName" />
<button (click)="save()">Save</button>
<button (click)="cancel()">Cancel</button>
} @else {
<h2>{{ user().name }}</h2>
<p>{{ user().email }}</p>
@if (editable()) {
<button (click)="edit()">Edit</button>
}
}
</div>
`,
styleUrl: './user-profile.component.scss',
})
export class UserProfileComponent {
// 输入信号
user = input.required<User>();
editable = input(false);
// 输出
updated = output<User>();
// 内部信号
isEditing = signal(false);
editedName = signal('');
// 计算属性
initials = computed(() => {
return this.user()
.name.split(' ')
.map((n) => n[0])
.join('')
.toUpperCase();
});
edit() {
this.editedName.set(this.user().name);
this.isEditing.set(true);
}
save() {
this.updated.emit({ ...this.user(), name: this.editedName() });
this.isEditing.set(false);
}
cancel() {
this.isEditing.set(false);
}
}
使用依赖注入的服务
// services/user.service.ts
import { Injectable, inject, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';
import { catchError, map, of } from 'rxjs';
interface User {
id: string;
name: string;
email: string;
}
@Injectable({
providedIn: 'root',
})
export class UserService {
private http = inject(HttpClient);
private apiUrl = '/api/users';
// 基于信号的状态
private _users = signal<User[]>([]);
private _loading = signal(false);
private _error = signal<string | null>(null);
// 公共只读信号
users = this._users.asReadonly();
loading = this._loading.asReadonly();
error = this._error.asReadonly();
async fetchUsers() {
this._loading.set(true);
this._error.set(null);
this.http
.get<User[]>(this.apiUrl)
.pipe(
catchError((err) => {
this._error.set(err.message);
return of([]);
})
)
.subscribe((users) => {
this._users.set(users);
this._loading.set(false);
});
}
async createUser(data: Omit<User, 'id'>) {
return this.http.post<User>(this.apiUrl, data).pipe(
map((user) => {
this._users.update((users) => [...users, user]);
return user;
})
);
}
async updateUser(id: string, data: Partial<User>) {
return this.http.patch<User>(`${this.apiUrl}/${id}`, data).pipe(
map((updated) => {
this._users.update((users) =>
users.map((u) => (u.id === id ? updated : u))
);
return updated;
})
);
}
}
响应式表单
// components/user-form.component.ts
import { Component, inject, output } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
ReactiveFormsModule,
FormBuilder,
FormGroup,
Validators,
} from '@angular/forms';
@Component({
selector: 'app-user-form',
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
template: `
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="name">姓名</label>
<input id="name" formControlName="name" />
@if (form.get('name')?.errors?.['required'] && form.get('name')?.touched) {
<span class="error">姓名是必填项</span>
}
</div>
<div class="form-group">
<label for="email">邮箱</label>
<input id="email" type="email" formControlName="email" />
@if (form.get('email')?.errors?.['email'] && form.get('email')?.touched) {
<span class="error">邮箱格式无效</span>
}
</div>
<div class="form-group">
<label for="password">密码</label>
<input id="password" type="password" formControlName="password" />
@if (form.get('password')?.errors?.['minlength'] && form.get('password')?.touched) {
<span class="error">密码至少需要8个字符</span>
}
</div>
<button type="submit" [disabled]="form.invalid">提交</button>
</form>
`,
})
export class UserFormComponent {
private fb = inject(FormBuilder);
submitted = output<{ name: string; email: string; password: string }>();
form: FormGroup = this.fb.group({
name: ['', [Validators.required]],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
});
onSubmit() {
if (this.form.valid) {
this.submitted.emit(this.form.value);
}
}
}
路由配置
// app.routes.ts
import { Routes } from '@angular/router';
import { authGuard } from './guards/auth.guard';
export const routes: Routes = [
{
path: '',
loadComponent: () =>
import('./pages/home/home.component').then((m) => m.HomeComponent),
},
{
path: 'login',
loadComponent: () =>
import('./pages/login/login.component').then((m) => m.LoginComponent),
},
{
path: 'dashboard',
canActivate: [authGuard],
loadComponent: () =>
import('./pages/dashboard/dashboard.component').then(
(m) => m.DashboardComponent
),
},
{
path: 'users',
canActivate: [authGuard],
loadChildren: () =>
import('./features/users/users.routes').then((m) => m.USERS_ROUTES),
},
{
path: '**',
loadComponent: () =>
import('./pages/not-found/not-found.component').then(
(m) => m.NotFoundComponent
),
},
];
// guards/auth.guard.ts
import { inject } from '@angular/core';
import { Router, type CanActivateFn } from '@angular/router';
import { AuthService } from '../services/auth.service';
export const authGuard: CanActivateFn = () => {
const auth = inject(AuthService);
const router = inject(Router);
if (auth.isAuthenticated()) {
return true;
}
return router.createUrlTree(['/login']);
};
最佳实践
- 默认使用独立组件
- 利用信号进行响应式状态管理
- 为路由实现懒加载
- 对复杂表单使用响应式表单
- 应用依赖注入模式
目标流程
- 企业级Angular开发
- 前端架构设计
- 表单验证实现
- 状态管理设置