文档
Angular 入门教程:企业级框架核心概念
一、Angular 是什么?
Angular 是由 Google 维护的企业级前端框架(2016 年发布 Angular 2,与 2010 年的 AngularJS 完全不同)。它是一个完整的解决方案——包含路由、表单、HTTP 客户端、状态管理、测试工具、SSR,开箱即用。使用 TypeScript 开发,强制采用 RxJS 进行异步编程。
核心哲学
"电池全包含"——不让你纠结选什么路由库、状态管理,Angular 都提供了官方方案。
二、核心概念地图
NgModule(模块)
├── Component(组件)—— 视图 + 逻辑
│ ├── Template(HTML 模板)
│ └── Class(TypeScript 类)
├── Service(服务)—— 业务逻辑,可注入
│ └── @Injectable()
├── Pipe(管道)—— 数据转换
└── Directive(指令)—— 行为增强
Standalone Components(Angular 15+)
@Component({
standalone: true, // 不再需要 NgModule
imports: [CommonModule], // 直接导入依赖
template: `<h1>{{ title }}</h1>`,
})
export class MyComponent {
title = "Hello";
}
三、数据绑定四种方式
<!-- 1. 插值:组件 → 模板 -->
<h1>{{ title }}</h1>
<!-- 2. 属性绑定:组件 → 模板(用方括号) -->
<img [src]="imageUrl" />
<!-- 3. 事件绑定:模板 → 组件(用圆括号) -->
<button (click)="onSave()">保存</button>
<!-- 4. 双向绑定:双向同步(香蕉盒 [()]) -->
<input [(ngModel)]="username" />
四、控制流(Angular 17+ 新语法)
<!-- @if / @else -->
@if (user(); as user) {
<p>欢迎, {{ user.name }}</p>
} @else {
<p>请登录</p>
}
<!-- @for(替代 *ngFor) -->
@for (item of items; track item.id; let i = $index) {
<li>{{ i + 1 }}. {{ item.name }}</li>
} @empty {
<li>列表为空</li>
}
<!-- @switch -->
@switch (status) {
@case ("loading") { <spinner /> }
@case ("error") { <error /> }
@default { <content /> }
}
五、依赖注入(DI)
Angular 的核心优势之一:
@Injectable({ providedIn: "root" }) // 应用级单例
export class AuthService {
private user = signal<User | null>(null);
login(credentials: Credentials): Observable<User> {
return this.http.post<User>("/api/login", credentials).pipe(
tap((user) => this.user.set(user))
);
}
}
@Component({ /* ... */ })
export class LoginComponent {
// 自动注入,无需手动创建
constructor(private auth: AuthService) {}
}
六、Signal vs RxJS
Angular 16+ 引入 Signals,与 RxJS 互补:
| Signal | RxJS Observable | |
|---|---|---|
| 读取 | count() 同步 |
.subscribe() 异步 |
| 用途 | 组件状态 | 异步流、HTTP、WebSocket |
| 示例 | count = signal(0) |
http.get("/api") |
| 转换 | computed() |
.pipe(map()) |
// 互操作
const obs$ = this.http.get<User[]>("/api/users"); // Observable
const users = toSignal(obs$, { initialValue: [] }); // 转为 Signal
const count = signal(0);
const count$ = toObservable(count); // 转为 Observable
七、路由
const routes: Routes = [
{ path: "", component: HomeComponent },
{ path: "products", component: ProductListComponent },
{ path: "products/:id", component: ProductDetailComponent },
{
path: "admin",
canActivate: [AuthGuard], // 路由守卫
loadChildren: () => import("./admin/admin.routes"), // 懒加载
},
{ path: "**", component: NotFoundComponent }, // 通配 404
];
<!-- router-outlet 是路由组件的渲染出口 -->
<router-outlet />
<!-- routerLink 声明式导航 -->
<a routerLink="/products" routerLinkActive="active">产品</a>
八、HTTP 客户端
import { HttpClient } from "@angular/common/http";
@Injectable({ providedIn: "root" })
export class ProductService {
constructor(private http: HttpClient) {}
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>("/api/products");
}
createProduct(data: Partial<Product>): Observable<Product> {
return this.http.post<Product>("/api/products", data);
}
deleteProduct(id: number): Observable<void> {
return this.http.delete<void>(`/api/products/${id}`);
}
}
九、最佳实践
- 使用 Standalone Components(Angular 15+),告别 NgModule 样板
- Signals 优先于传统双向绑定,逐步替代 RxJS 在组件状态中的使用
- OnPush 变更检测:
changeDetection: ChangeDetectionStrategy.OnPush提升性能 - Lazy Loading:每个功能模块独立懒加载
track函数:@for中始终提供 track 表达式
十、思考题
- Angular 的依赖注入与 React Context 有什么本质区别?
- 为什么 Angular 选择 RxJS 作为异步基础,而不是 Promise?
- Signals 会完全取代 RxJS 在 Angular 中的地位吗?