# angular-coding
> 综合Angular编码技能,涵盖组件开发、状态管理、路由配置、API服务、测试和质量保证、构建部署等核心领域,用于解决Angular开发中的各种编码问题。
- Author: sunjuzhong
- Repository: sjzsdu/skills
- Version: 20251225150921
- Stars: 0
- Forks: 0
- Last Updated: 2026-02-07
- Source: https://github.com/sjzsdu/skills
- Web: https://mule.run/skillshub/@@sjzsdu/skills~angular-coding:20251225150921
---
---
name: angular-coding
description: "综合Angular编码技能,涵盖组件开发、状态管理、路由配置、API服务、测试和质量保证、构建部署等核心领域,用于解决Angular开发中的各种编码问题。"
license: Apache 2.0
---
# Angular编码综合技能
## 概述
本技能提供Angular开发的综合指南,涵盖组件开发、状态管理、路由配置、API服务、测试和质量保证、构建部署等核心领域,帮助前端开发人员解决Angular编码中的各种问题,提高开发效率和代码质量。
## 核心内容
### 1. 组件开发
#### 基本组件结构(使用信号)
```typescript
import { Component, input, output } from '@angular/core';
@Component({
selector: 'app-user-profile',
template: `
{{ user().name }}
{{ user().email }}
`,
styles: [`
.user-profile { padding: 16px; border: 1px solid #e0e0e0; border-radius: 8px; }
`]
})
export class UserProfileComponent {
user = input.required<{ id: string; name: string; email: string }>();
onContact = output();
}
```
#### 表单处理
```typescript
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-user-form',
template: `
`
})
export class UserFormComponent {
userForm: FormGroup;
constructor(private fb: FormBuilder) {
this.userForm = this.fb.group({
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
}
onSubmit() {
if (this.userForm.valid) {
console.log('Form submitted:', this.userForm.value);
}
}
}
```
#### 使用model()进行双向绑定
```typescript
import { Component, model } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
{{ count() }}
`,
styles: [
.counter { display: flex; align-items: center; gap: 16px; }
]
})
export class CounterComponent {
count = model(0);
increment() {
this.count.update(current => current + 1);
}
decrement() {
this.count.update(current => Math.max(0, current - 1));
}
}
// 使用示例
//
#### 基于Formly的动态表单
```typescript
import { Component, signal } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormlyFormOptions, FormlyFieldConfig } from '@ngx-formly/core';
import { FormlyNzFormModule } from '@ngx-formly/ng-zorro-antd';
@Component({
selector: 'app-dynamic-form',
template: `
`,
styles: [
.dynamic-form { padding: 16px; border: 1px solid #e0e0e0; border-radius: 8px; }
.form-result { margin-top: 16px; padding: 16px; background: #f5f5f5; border-radius: 8px; }
]
})
export class DynamicFormComponent {
form = new FormGroup({});
model = signal({
name: '',
email: '',
age: null,
gender: '',
address: {
street: '',
city: '',
zipCode: ''
}
});
options: FormlyFormOptions = {};
fields = signal([
{
key: 'name',
type: 'input',
props: {
label: '姓名',
placeholder: '请输入姓名',
required: true,
},
},
{
key: 'email',
type: 'input',
props: {
label: '邮箱',
placeholder: '请输入邮箱',
required: true,
type: 'email',
},
validators: {
validation: ['email'],
},
},
{
key: 'age',
type: 'input',
props: {
label: '年龄',
placeholder: '请输入年龄',
type: 'number',
min: 18,
max: 100,
},
},
{
key: 'gender',
type: 'select',
props: {
label: '性别',
placeholder: '请选择性别',
options: [
{ label: '男', value: 'male' },
{ label: '女', value: 'female' },
],
},
},
{
key: 'address',
type: 'fieldset',
props: {
label: '地址',
},
fieldGroup: [
{
key: 'street',
type: 'input',
props: {
label: '街道',
placeholder: '请输入街道',
},
},
{
key: 'city',
type: 'input',
props: {
label: '城市',
placeholder: '请输入城市',
},
},
{
key: 'zipCode',
type: 'input',
props: {
label: '邮编',
placeholder: '请输入邮编',
},
},
],
},
]);
submitted = signal(false);
onSubmit() {
if (this.form.valid) {
this.submitted.set(true);
console.log('Form submitted:', this.model());
}
}
}
```
### 2. 状态管理和路由
#### 路由配置
```typescript
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
},
{
path: 'user/:id',
component: UserComponent,
canActivate: [AuthGuard],
resolve: { user: UserResolver }
},
{ path: '404', component: NotFoundComponent },
{ path: '**', redirectTo: '/404' }
];
@NgModule({
imports: [RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules,
scrollPositionRestoration: 'enabled'
})],
exports: [RouterModule]
})
export class AppRoutingModule { }
```
#### 信号(Signals)状态管理
```typescript
import { Component, signal, computed, effect } from '@angular/core';
@Component({
selector: 'app-todo-list',
template: `
Todo List
{{ completedCount() }} / {{ todos().length }} completed
`
})
export class TodoListComponent {
todos = signal([
{ id: 1, title: 'Learn Angular', completed: true },
{ id: 2, title: 'Build app', completed: false }
]);
completedCount = computed(() =>
this.todos().filter(todo => todo.completed).length
);
constructor() {
effect(() => {
console.log(`Todo count changed: ${this.todos().length}`);
});
}
updateTodo(todo: any) {
this.todos.update(todos =>
todos.map(t => t.id === todo.id ? todo : t)
);
}
}
```
### 3. API服务开发
#### 基本服务实现
```typescript
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class UserService {
private apiUrl = 'https://api.example.com/users';
constructor(private http: HttpClient) { }
getUsers(): Observable {
return this.http.get(this.apiUrl);
}
getUserById(id: string): Observable {
return this.http.get(`${this.apiUrl}/${id}`);
}
createUser(user: any): Observable {
return this.http.post(this.apiUrl, user);
}
}
```
#### HTTP拦截器
```typescript
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest, next: HttpHandler): Observable> {
const token = localStorage.getItem('authToken');
if (token) {
const cloned = req.clone({
headers: req.headers.set('Authorization', 'Bearer ' + token)
});
return next.handle(cloned);
}
return next.handle(req);
}
}
```
### 4. 测试和质量保证
#### 单元测试
```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UserProfileComponent } from './user-profile.component';
describe('UserProfileComponent', () => {
let component: UserProfileComponent;
let fixture: ComponentFixture;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ UserProfileComponent ]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(UserProfileComponent);
component = fixture.componentInstance;
component.user.set({ id: '1', name: 'John', email: 'john@example.com' });
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
it('should emit event when button is clicked', () => {
spyOn(component.onContact, 'emit');
const button = fixture.nativeElement.querySelector('button');
button.click();
expect(component.onContact.emit).toHaveBeenCalledWith('1');
});
});
```
#### ESLint配置
```json
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@angular-eslint/recommended",
"plugin:prettier/recommended"
],
"rules": {
"@angular-eslint/component-selector": [
"error", { "type": "element", "prefix": "app", "style": "kebab-case" }
]
}
}
```
### 5. 构建和部署
#### 构建命令
```bash
# 开发构建
ng build
# 生产构建
ng build --configuration production
# 构建并分析
ng build --configuration production --stats-json
npx webpack-bundle-analyzer dist/my-app/stats.json
```
#### GitHub Actions CI配置
```yaml
name: Angular CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with: { node-version: 18.x, cache: 'npm' }
- run: npm ci
- run: npm run build -- --configuration production
- run: npm test -- --watch=false --browsers=ChromeHeadless
```
## 最佳实践
### 组件开发
- 使用OnPush变更检测策略提高性能
- 组件应该保持小巧和单一职责
- **使用基于信号的输入/输出**:优先使用`input()`、`output()`和`model()`函数进行组件通信
- 避免在模板中使用复杂表达式
- 为组件编写单元测试
- **动态表单使用Formly**:复杂表单推荐使用@ngx-formly/core和@ngx-formly/ng-zorro-antd,提高表单开发效率和可维护性
- **Formly字段配置最佳实践**:
- 将字段配置封装为可复用的函数或服务
- 使用类型安全的字段配置
- 合理使用字段组和嵌套字段
- 为复杂表单实现懒加载字段配置
### 状态管理
- 简单状态使用Signals,复杂状态使用NgRx
- 保持状态不可变
- 避免全局状态膨胀
- 为状态管理编写测试
### API服务
- 使用拦截器处理通用逻辑
- 实现适当的缓存策略
- 使用类型安全的API响应
- 实现全局错误处理
### 路由
- 使用懒加载减少初始包大小
- 实现路由守卫保护敏感路由
- 使用解析器预加载数据
- 配置适当的404页面
### 性能优化
- 启用树摇和代码分割
- 优化大型列表(虚拟滚动、分页)
- 使用CDN分发静态资源
- 监控应用性能指标
### 基于信号的组件通信最佳实践
- 使用`input.required()`表示必填输入
- 使用`input()`带默认值表示可选输入
- 使用`output()`发送事件
- 使用`model()`实现双向绑定
- 在模板中使用`signal()`时需要调用(如`user().name`)
- 避免在模板中直接修改信号值
- 使用`update()`方法更新信号值,保持不可变性
## 常见问题解决方案
### 1. 组件不更新
**问题**:组件数据更新但视图不刷新
**解决方案**:
- 检查变更检测策略
- 确保使用不可变数据更新
- 手动触发变更检测(如果需要)
- 检查是否正确使用了Input/Output
### 2. 路由无法导航
**问题**:点击链接或调用router.navigate()无效果
**解决方案**:
- 检查路由配置
- 检查路由守卫
- 检查是否使用了正确的路由路径
- 检查是否正确导入了RouterModule
### 3. API请求失败
**问题**:HTTP请求返回错误
**解决方案**:
- 检查API端点URL
- 检查请求头配置
- 检查CORS配置
- 检查网络连接
- 实现适当的错误处理
### 4. 构建失败
**问题**:ng build命令失败
**解决方案**:
- 检查TypeScript错误
- 检查依赖项版本
- 检查angular.json配置
- 清理node_modules并重新安装
## 依赖项
- **@angular/core**: Angular核心库
- **@angular/common/http**: HTTP客户端
- **@angular/forms**: 表单处理
- **@angular/router**: 路由管理
- **@ngx-formly/core**: 动态表单核心库
- **@ngx-formly/ng-zorro-antd**: NG-ZORRO UI组件的Formly集成
- **@ngrx/store**: 状态管理(可选)
- **jasmine-core/karma**: 单元测试
- **cypress**: 端到端测试
- **eslint/prettier**: 代码质量
## 总结
本技能提供了Angular开发的综合指南,涵盖了从组件开发到构建部署的各个方面。通过遵循本技能中的最佳实践和代码示例,您可以解决Angular编码中的各种问题,创建高质量、可维护的Angular应用。