Angular
分类: 前端
Angular教程
目录
Angular简介
环境搭建
TypeScript基础
组件基础
模板语法
指令系统
服务与依赖注入
路由系统
表单处理
HTTP与网络请求
状态管理
RxJS响应式编程
生命周期
测试
性能优化
最佳实践
一、Angular简介
1.1 什么是Angular
Angular是由Google开发和维护的前端框架,是一个完整的企业级应用开发平台。它提供了从模板语法到依赖注入、从路由管理到HTTP客户端的完整解决方案。Angular采用TypeScript作为开发语言,提供了强类型支持、装饰器语法和模块化的架构设计。
Angular最初于2010年以AngularJS的名称发布,是Angular的1.x版本。2016年,Angular 2正式发布,这是一个完全重写的版本,与AngularJS不兼容。之后的版本采用语义化版本号,如Angular 4、5、6等,目前最新版本是Angular 17+。
Angular的核心特性包括:双向数据绑定、依赖注入、指令系统、组件化开发、路由系统、表单处理、HTTP客户端、RxJS集成等。这些特性使Angular特别适合开发大型企业级应用。
1.2 Angular核心概念
概念 说明
组件 UI的基本构建块
模块 相关的组件、服务、指令的集合
服务 业务逻辑和数据访问
指令 扩展HTML元素的行为
模板 声明式的视图定义
依赖注入 管理对象依赖的机制
1.3 Angular与其他框架对比
框架 特点 学习曲线 适用场景
Angular 完整解决方案、TypeScript优先 较陡 大型企业级应用
React 灵活、组件化、生态丰富 中等 中大型应用
Vue 简单易学、文档友好 较平缓 中小型应用
二、环境搭建
2.1 安装Node.js和npm
Angular需要Node.js和npm环境。首先需要安装Node.js,建议使用LTS(长期支持)版本。
检查Node.js版本
node -v
检查npm版本
npm -v
推荐Node.js版本:18.x或更高
推荐npm版本:9.x或更高
2.2 安装Angular CLI
Angular CLI是Angular官方提供的命令行工具,用于快速搭建项目和生成代码。
全局安装Angular CLI
npm install -g @angular/cli
检查Angular CLI版本
ng version
创建新项目
ng new my-angular-app
进入项目目录
cd my-angular-app
启动开发服务器
ng serve
或者简写
ng s
创建项目时,CLI会提示选择一些配置选项,包括是否添加路由、选择CSS预处理器等。
2.3 项目结构
my-angular-app/
├── e2e/ # 端到端测试
├── src/ # 源代码
│ ├── app/ # 应用代码
│ │ ├── components/ # 组件目录
│ │ ├── services/ # 服务目录
│ │ ├── models/ # 数据模型
│ │ ├── app.component.ts # 根组件
│ │ ├── app.module.ts # 根模块
│ │ └── app-routing.module.ts # 路由模块
│ ├── assets/ # 静态资源
│ ├── environments/ # 环境配置
│ ├── styles.css # 全局样式
│ └── main.ts # 应用入口
├── angular.json # Angular配置文件
├── package.json # 项目依赖配置
└── tsconfig.json # TypeScript配置
2.4 常用CLI命令
生成组件
ng generate component components/user-list
ng g c components/user-list
生成服务
ng generate service services/user
ng g s services/user
生成类
ng generate class models/user
生成接口
ng generate interface models/user
生成模块
ng generate module modules/admin
生成路由
ng generate routing
构建项目
ng build
运行测试
ng test
代码检查
ng lint
三、TypeScript基础
3.1 TypeScript简介
TypeScript是JavaScript的超集,添加了类型系统和其他高级特性。Angular使用TypeScript作为开发语言,利用其类型系统提高代码质量和开发体验。
// 类型声明
let name: string = "张三";
let age: number = 25;
let isActive: boolean = true;
// 数组
let numbers: number[] = [1, 2, 3];
let names: Array = ["a", "b", "c"];
// 对象
let user: { name: string; age: number } = {
name: "张三",
age: 25
};
// 接口
interface User {
name: string;
age: number;
email?: string; // 可选属性
}
let user2: User = {
name: "李四",
age: 30
};
// 类型别名
type ID = string | number;
let userId: ID = "12345";
3.2 函数
// 函数类型
function add(a: number, b: number): number {
return a + b;
}
// 箭头函数
const multiply = (a: number, b: number): number => a * b;
// 可选参数
function greet(name: string, greeting?: string): string {
return greeting ? ${greeting}, ${name}! : Hello, ${name}!;
}
// 默认参数
function createUser(name: string, role: string = "user"): User {
return { name, role };
}
// 剩余参数
function sum(...numbers: number[]): number {
return numbers.reduce((a, b) => a + b, 0);
}
3.3 类
// 类的定义
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
introduce(): string {
return 我叫${this.name},今年${this.age}岁;
}
}
// 继承
class Student extends Person {
grade: string;
constructor(name: string, age: number, grade: string) {
super(name, age);
this.grade = grade;
}
introduce(): string {
return ${super.introduce()},在${this.grade}年级;
}
}
// 访问修饰符
class User {
public name: string; // 公开
private age: number; // 私有
protected email: string; // 受保护
constructor(name: string, age: number, email: string) {
this.name = name;
this.age = age;
this.email = email;
}
}
3.4 装饰器
装饰器是Angular的核心特性之一,用于给类、方法、属性添加元数据。
// 装饰器示例
@Component({
selector: "app-user",
templateUrl: "./user.component.html",
styleUrls: ["./user.component.css"]
})
export class UserComponent implements OnInit {
@Input() user: User;
@Output() delete = new EventEmitter();
@ViewChild("inputElement") inputElement: ElementRef;
ngOnInit(): void {
console.log("组件初始化");
}
}
常见装饰器包括:@Component(组件)、@Injectable(服务)、@Input(输入属性)、@Output(输出属性)、@ViewChild(视图子元素)等。
四、组件基础
4.1 组件定义
Angular组件由三个主要部分组成:装饰器、元数据、类定义。
// user.component.ts
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-user",
templateUrl: "./user.component.html",
styleUrls: ["./user.component.css"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserComponent implements OnInit {
// 属性
username: string = "张三";
age: number = 25;
isActive: boolean = true;
items: string[] = ["苹果", "香蕉", "橙子"];
// 构造函数
constructor() {}
// 生命周期钩子
ngOnInit(): void {
// 初始化逻辑
}
// 方法
onClick(): void {
console.log("按钮点击");
}
onDelete(item: string): void {
console.log("删除:", item);
}
}
4.2 组件模板
{{ username }}
年龄:{{ age }}
状态:{{ isActive ? "活跃" : "不活跃" }}
4.3 组件样式
/ user.component.css /
.user-card {
padding: 16px;
border: 1px solid #ddd;
border-radius: 8px;
max-width: 300px;
}
h2 {
color: #333;
margin-bottom: 12px;
}
ul {
list-style: none;
padding: 0;
}
li {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #eee;
}
button {
padding: 8px 16px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
4.4 组件通信
方式 说明
@Input 父组件向子组件传递数据
@Output 子组件向父组件发送事件
ViewChild 父组件访问子组件
服务 跨组件共享数据
// 子组件
import { Component, Input, Output, EventEmitter } from "@angular/core";
@Component({
selector: "app-child",
template: <button (click)="sendToParent()">发送数据</button>
})
export class ChildComponent {
@Input() data: string = "";
@Output() event = new EventEmitter();
sendToParent(): void {
this.event.emit("来自子组件的数据");
}
}
// 父组件
@Component({
selector: "app-parent",
template: <app-child
[data]="parentData"
(event)="handleEvent($event)">
</app-child>
})
export class ParentComponent {
parentData = "来自父组件";
handleEvent(data: string): void {
console.log("收到:", data);
}
}
五、模板语法
5.1 数据绑定
Angular支持多种数据绑定方式。
绑定类型 语法 说明
插值 {{ value }} 单向显示
属性绑定 [property]="value" 单向设置属性
事件绑定 (event)="handler" 单向绑定事件
双向绑定 [(ngModel)]="value" 双向数据同步
用户名:{{ username }}
计算结果:{{ 1 + 1 }}
输入:{{ username }}
5.2 内置指令
Angular提供了多个内置指令。
显示内容
显示
备用内容
-
{{ i }} - {{ item.name }}
5.3 管道
管道用于在模板中转换数据的显示格式。
{{ name | uppercase }}
{{ date | date:'yyyy-MM-dd' }}
{{ number | currency:'CNY' }}
{{ json | json }}
{{ text | slice:0:10 }}
{{ date | date:'fullDate' | uppercase }}
常用内置管道包括:date(日期格式化)、currency(货币格式化)、uppercase/ lowercase(大写/小写)、number(数字格式化)、percent(百分比)、json(JSON格式化)、slice(截取)、async(异步管道)。
六、指令系统
6.1 组件指令
组件是带有模板的指令,是Angular应用的主要构建块。
@Component({
selector: "app-greeting",
template: `
{{ message }}
`,
styles: [`
.greeting {
padding: 16px;
background: #f5f5f5;
}
`]
})
export class GreetingComponent {
@Input() message: string = "Hello!";
}
6.2 属性指令
属性指令用于改变元素的外观或行为。
import { Directive, ElementRef, Renderer2, Input } from "@angular/core";
@Directive({
selector: "[appHighlight]"
})
export class HighlightDirective {
@Input() appHighlight: string = "yellow";
constructor(private el: ElementRef, private renderer: Renderer2) {}
ngOnInit(): void {
this.renderer.setStyle(
this.el.nativeElement,
"background-color",
this.appHighlight
);
}
}
高亮文本
6.3 结构指令
结构指令用于添加、移除或操作DOM元素。
import { Directive, Input, TemplateRef, ViewContainerRef } from "@angular/core";
@Directive({
selector: "[appUnless]"
})
export class UnlessDirective {
@Input() set appUnless(condition: boolean) {
if (!condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
constructor(
private templateRef: TemplateRef
,
private viewContainer: ViewContainerRef
) {}
}
七、服务与依赖注入
7.1 服务定义
服务用于封装可重用的业务逻辑和数据访问代码。
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
import { User } from "../models/user";
@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);
}
getUser(id: string): Observable {
return this.http.get(`${this.apiUrl}/${id}`);
}
createUser(user: User): Observable {
return this.http.post(this.apiUrl, user);
}
updateUser(id: string, user: User): Observable {
return this.http.put(`${this.apiUrl}/${id}`, user);
}
deleteUser(id: string): Observable {
return this.http.delete(`${this.apiUrl}/${id}`);
}
}
7.2 依赖注入
依赖注入是Angular的核心特性,允许将服务注入到组件或其他服务中。
import { Component, OnInit } from "@angular/core";
import { UserService } from "../services/user.service";
import { User } from "../models/user";
@Component({
selector: "app-user-list",
templateUrl: "./user-list.component.html"
})
export class UserListComponent implements OnInit {
users: User[] = [];
loading: boolean = false;
error: string = "";
constructor(private userService: UserService) {}
ngOnInit(): void {
this.loadUsers();
}
loadUsers(): void {
this.loading = true;
this.userService.getUsers().subscribe({
next: (data) => {
this.users = data;
this.loading = false;
},
error: (err) => {
this.error = err.message;
this.loading = false;
}
});
}
deleteUser(id: string): void {
this.userService.deleteUser(id).subscribe({
next: () => {
this.users = this.users.filter(u => u.id !== id);
}
});
}
}
7.3 服务提供方式
方式 说明
providedIn: "root" 全局单例,整个应用共享
providedIn: "any" 每个懒加载模块创建新实例
组件providers 仅在当前组件及其子组件中可用
模块providers 在当前模块的所有组件中可用
八、路由系统
8.1 路由配置
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { HomeComponent } from "./components/home/home.component";
import { AboutComponent } from "./components/about/about.component";
import { UserComponent } from "./components/user/user.component";
import { UserDetailComponent } from "./components/user-detail/user-detail.component";
import { AuthGuard } from "./guards/auth.guard";
const routes: Routes = [
{ path: "", redirectTo: "/home", pathMatch: "full" },
{ path: "home", component: HomeComponent },
{ path: "about", component: AboutComponent },
{
path: "users",
component: UserComponent,
canActivate: [AuthGuard]
},
{
path: "users/:id",
component: UserDetailComponent,
resolve: { user: UserResolver }
},
{ path: "**", component: NotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
8.2 路由导航
import { Router, ActivatedRoute } from "@angular/router";
export class SomeComponent {
userId = "123";
constructor(
private router: Router,
private route: ActivatedRoute
) {}
goToUser(): void {
// 导航到指定路由
this.router.navigate(["/users", this.userId]);
// 带查询参数
this.router.navigate(["/users", this.userId], {
queryParams: { page: 1, sort: "name" }
});
// 导航到根路由
this.router.navigate(["/home"]);
}
// 获取路由参数
ngOnInit(): void {
this.route.paramMap.subscribe(params => {
const id = params.get("id");
console.log("用户ID:", id);
});
this.route.queryParamMap.subscribe(queryParams => {
const page = queryParams.get("page");
console.log("页码:", page);
});
}
}
8.3 路由守卫
// 路由守卫类型
// CanActivate - 决定是否可以激活路由
// CanActivateChild - 决定是否可以激活子路由
// CanDeactivate - 决定是否可以离开路由
// Resolve - 路由解析预加载数据
// CanLoad - 决定是否可以加载懒加载模块
// 认证守卫示例
@Injectable({
providedIn: "root"
})
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router
) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean | UrlTree {
if (this.authService.isAuthenticated()) {
return true;
}
return this.router.createUrlTree(["/login"], {
queryParams: { returnUrl: state.url }
});
}
}
九、表单处理
9.1 模板驱动表单
模板驱动表单使用Angular指令处理表单,适合简单场景。
import { Component } from "@angular/core";
@Component({
selector: "app-login",
template: `
`
})
export class LoginComponent {
user = {
username: "",
password: ""
};
onSubmit(form: NgForm): void {
console.log("表单提交:", form.value);
}
}
9.2 响应式表单
响应式表单使用TypeScript类定义表单结构,适合复杂场景。
import { Component, OnInit } from "@angular/core";
import { FormBuilder, FormGroup, Validators, AbstractControl, ValidationErrors } from "@angular/forms";
@Component({
selector: "app-register",
template: `
`
})
export class RegisterComponent implements OnInit {
registerForm!: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.registerForm = this.fb.group({
username: ["", [Validators.required, Validators.minLength(3)]],
email: ["", [Validators.required, Validators.email]],
passwordGroup: this.fb.group({
password: ["", [Validators.required, Validators.minLength(6)]],
confirmPassword: ["", [Validators.required]]
}, { validators: this.passwordMatcher })
});
}
passwordMatcher: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
const password = control.get("password");
const confirmPassword = control.get("confirmPassword");
return password?.value !== confirmPassword?.value ? { passwordMismatch: true } : null;
};
get username() { return this.registerForm.get("username"); }
get email() { return this.registerForm.get("email"); }
get passwordGroup() { return this.registerForm.get("passwordGroup"); }
get confirmPassword() { return this.registerForm.get("passwordGroup.confirmPassword"); }
onSubmit(): void {
if (this.registerForm.valid) {
console.log("表单提交:", this.registerForm.value);
}
}
}
十、HTTP与网络请求
10.1 HttpClient
Angular的HttpClient用于发起HTTP请求。
import { HttpClient, HttpHeaders, HttpParams } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs";
import { User } from "../models/user";
@Injectable({
providedIn: "root"
})
export class ApiService {
private baseUrl = "https://api.example.com";
constructor(private http: HttpClient) {}
// GET请求
getUsers(): Observable {
return this.http.get(`${this.baseUrl}/users`);
}
getUser(id: string): Observable {
return this.http.get(`${this.baseUrl}/users/${id}`);
}
// 带参数的GET请求
searchUsers(query: string, page: number): Observable {
const params = new HttpParams()
.set("q", query)
.set("page", page.toString());
return this.http.get(`${this.baseUrl}/users/search`, { params });
}
// POST请求
createUser(user: User): Observable {
return this.http.post(`${this.baseUrl}/users`, user);
}
// PUT请求
updateUser(id: string, user: User): Observable {
return this.http.put(`${this.baseUrl}/users/${id}`, user);
}
// PATCH请求
patchUser(id: string, partialUser: Partial): Observable {
return this.http.patch(`${this.baseUrl}/users/${id}`, partialUser);
}
// DELETE请求
deleteUser(id: string): Observable {
return this.http.delete(`${this.baseUrl}/users/${id}`);
}
// 自定义请求头
getWithHeaders(): Observable {
const headers = new HttpHeaders()
.set("Authorization", "Bearer token")
.set("X-Custom-Header", "value");
return this.http.get(`${this.baseUrl}/users`, { headers });
}
}
10.2 HTTP拦截器
拦截器用于统一处理请求或响应。
import { Injectable } from "@angular/core";
import {
HttpInterceptor,
HttpRequest,
HttpHandler,
HttpEvent,
HttpErrorResponse
} from "@angular/common/http";
import { Observable, throwError } from "rxjs";
import { catchError } from "rxjs/operators";
import { Router } from "@angular/router";
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private router: Router) {}
intercept(
request: HttpRequest,
next: HttpHandler
): Observable> {
// 获取token
const token = localStorage.getItem("auth_token");
if (token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401) {
// 未授权,跳转到登录页
this.router.navigate(["/login"]);
}
return throwError(() => error);
})
);
}
}
十一、状态管理
11.1 服务+RxJS
对于中小型应用,可以使用服务配合RxJS管理状态。
import { Injectable } from "@angular/core";
import { BehaviorSubject, Observable } from "rxjs";
import { User } from "../models/user";
@Injectable({
providedIn: "root"
})
export class UserStateService {
private usersSubject = new BehaviorSubject([]);
private loadingSubject = new BehaviorSubject(false);
users$ = this.usersSubject.asObservable();
loading$ = this.loadingSubject.asObservable();
setUsers(users: User[]): void {
this.usersSubject.next(users);
}
addUser(user: User): void {
const currentUsers = this.usersSubject.getValue();
this.usersSubject.next([...currentUsers, user]);
}
updateUser(updatedUser: User): void {
const currentUsers = this.usersSubject.getValue();
const index = currentUsers.findIndex(u => u.id === updatedUser.id);
if (index !== -1) {
const newUsers = [...currentUsers];
newUsers[index] = updatedUser;
this.usersSubject.next(newUsers);
}
}
deleteUser(id: string): void {
const currentUsers = this.usersSubject.getValue();
this.usersSubject.next(currentUsers.filter(u => u.id !== id));
}
setLoading(loading: boolean): void {
this.loadingSubject.next(loading);
}
}
11.2 NgRx
NgRx是Angular的状态管理库,提供Redux模式实现。
# 安装NgRx
npm install @ngrx/store @ngrx/effects @ngrx/store-devtools
// user.actions.ts
import { createAction, props } from "@ngrx/store";
import { User } from "../models/user";
export const loadUsers = createAction("[User] Load Users");
export const loadUsersSuccess = createAction(
"[User] Load Users Success",
props<{ users: User[] }>()
);
export const loadUsersFailure = createAction(
"[User] Load Users Failure",
props<{ error: string }>()
);
// user.reducer.ts
import { createReducer, on } from "@ngrx/store";
import { User } from "../models/user";
import * as UserActions from "./user.actions";
export interface UserState {
users: User[];
loading: boolean;
error: string | null;
}
export const initialState: UserState = {
users: [],
loading: false,
error: null
};
export const userReducer = createReducer(
initialState,
on(UserActions.loadUsers, state => ({
...state,
loading: true
})),
on(UserActions.loadUsersSuccess, (state, { users }) => ({
...state,
users,
loading: false
})),
on(UserActions.loadUsersFailure, (state, { error }) => ({
...state,
error,
loading: false
}))
);
// user.effects.ts
import { Injectable } from "@angular/core";
import { Actions, createEffect, ofType } from "@ngrx/effects";
import { of } from "rxjs";
import { map, mergeMap, catchError } from "rxjs/operators";
import { UserService } from "../services/user.service";
import * as UserActions from "./user.actions";
@Injectable()
export class UserEffects {
loadUsers$ = createEffect(() =>
this.actions$.pipe(
ofType(UserActions.loadUsers),
mergeMap(() =>
this.userService.getUsers().pipe(
map(users => UserActions.loadUsersSuccess({ users })),
catchError(error => of(UserActions.loadUsersFailure({ error: error.message })))
)
)
)
);
constructor(
private actions$: Actions,
private userService: UserService
) {}
}
十二、RxJS响应式编程
12.1 RxJS基础
RxJS是响应式编程的库,Angular中广泛使用。
操作符 说明
map 转换每个值
filter 过滤值
reduce 聚合值
switchMap 切换到新的Observable
mergeMap 合并Observable
concatMap 串行合并Observable
tap 副作用操作
catchError 错误处理
debounceTime 防抖
distinctUntilChanged 去重
import { Component, OnInit, OnDestroy } from "@angular/core";
import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged, takeUntil } from "rxjs/operators";
import { FormControl } from "@angular/forms";
@Component({
selector: "app-search",
template: `
`
})
export class SearchComponent implements OnInit, OnDestroy {
searchControl = new FormControl("");
private destroy$ = new Subject();
ngOnInit(): void {
this.searchControl.valueChanges.pipe(
debounceTime(300), // 300ms防抖
distinctUntilChanged(), // 值变化才触发
takeUntil(this.destroy$) // 组件销毁时取消订阅
).subscribe(value => {
console.log("搜索:", value);
// 执行搜索逻辑
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
12.2 常用场景
// 定时器
import { interval, timer } from "rxjs";
interval(1000).subscribe(n => console.log(n));
timer(2000).subscribe(() => console.log("2秒后执行"));
// 点击事件
import { fromEvent } from "rxjs";
fromEvent(document, "click").subscribe(event => console.log(event));
// HTTP请求
import { of } from "rxjs";
import { ajax } from "rxjs/ajax";
ajax.getJSON("https://api.example.com/data").subscribe(data => console.log(data));
// 组合多个Observable
import { merge, combineLatest, zip } from "rxjs";
const combined$ = combineLatest([observable1$, observable2$]);
十三、生命周期
13.1 组件生命周期钩子
钩子 说明
ngOnChanges 输入属性变化时
ngOnInit 组件初始化
ngDoCheck 自定义变更检测
ngAfterViewInit 视图初始化完成后
ngAfterViewChecked 视图变更检测后
ngAfterContentInit 内容投影初始化后
ngAfterContentChecked 内容投影变更检测后
ngOnDestroy 组件销毁前
13.2 生命周期示例
import {
Component,
OnInit,
OnChanges,
DoCheck,
AfterViewInit,
AfterViewChecked,
AfterContentInit,
AfterContentChecked,
OnDestroy,
SimpleChanges,
ViewChild,
ElementRef,
ContentChild
} from "@angular/core";
@Component({
selector: "app-lifecycle",
template: `
视图子元素
`
})
export class LifecycleComponent implements
OnInit,
OnChanges,
DoCheck,
AfterViewInit,
AfterViewChecked,
AfterContentInit,
AfterContentChecked,
OnDestroy {
@Input() data: string = "";
@ViewChild("viewChild") viewChild!: ElementRef;
@ContentChild("contentChild") contentChild!: ElementRef;
ngOnChanges(changes: SimpleChanges): void {
console.log("ngOnChanges:", changes);
}
ngOnInit(): void {
console.log("ngOnInit: 组件初始化");
}
ngDoCheck(): void {
console.log("ngDoCheck: 变更检测");
}
ngAfterViewInit(): void {
console.log("ngAfterViewInit: 视图初始化完成");
console.log("ViewChild:", this.viewChild);
}
ngAfterViewChecked(): void {
console.log("ngAfterViewChecked: 视图变更检测完成");
}
ngAfterContentInit(): void {
console.log("ngAfterContentInit: 内容投影初始化完成");
console.log("ContentChild:", this.contentChild);
}
ngAfterContentChecked(): void {
console.log("ngAfterContentChecked: 内容投影变更检测完成");
}
ngOnDestroy(): void {
console.log("ngOnDestroy: 组件即将销毁");
}
}
十四、测试
14.1 单元测试
Angular使用Jasmine作为测试框架,Karma作为测试运行器。
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { UserComponent } from "./user.component";
import { UserService } from "../services/user.service";
import { of } from "rxjs";
describe("UserComponent", () => {
let component: UserComponent;
let fixture: ComponentFixture;
let userService: jasmine.SpyObj;
beforeEach(async () => {
const spy = jasmine.createSpyObj("UserService", ["getUsers", "deleteUser"]);
await TestBed.configureTestingModule({
declarations: [UserComponent],
providers: [{ provide: UserService, useValue: spy }]
}).compileComponents();
userService = TestBed.inject(UserService) as jasmine.SpyObj;
});
beforeEach(() => {
fixture = TestBed.createComponent(UserComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
it("should load users on init", () => {
const mockUsers = [
{ id: "1", name: "张三", email: "zhangsan@example.com" }
];
userService.getUsers.and.returnValue(of(mockUsers));
component.ngOnInit();
expect(component.users).toEqual(mockUsers);
});
it("should call deleteUser on button click", () => {
component.users = [
{ id: "1", name: "张三", email: "zhangsan@example.com" }
];
userService.deleteUser.and.returnValue(of(undefined));
component.deleteUser("1");
expect(userService.deleteUser).toHaveBeenCalledWith("1");
});
});
14.2 集成测试
import { TestBed } from "@angular/core/testing";
import { RouterTestingModule } from "@angular/router/testing";
import { AppComponent } from "./app.component";
describe("AppComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [RouterTestingModule],
declarations: [AppComponent]
}).compileComponents();
});
it("should create the app", () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
});
十五、性能优化
15.1 变更检测优化
import { Component, ChangeDetectionStrategy } from "@angular/core";
@Component({
selector: "app-user",
template: `...`,
// OnPush策略:只有输入属性变化时才检测
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserComponent {
// 组件逻辑
}
15.2 懒加载
// 路由懒加载
const routes: Routes = [
{
path: "admin",
loadChildren: () =>
import("./modules/admin/admin.module").then(m => m.AdminModule)
}
];
15.3 其他优化
优化方式 说明
trackBy ngFor中使用trackBy优化列表渲染
AsyncPipe 使用async管道自动订阅Observable
Pure Pipes 使用纯管道
Preloading 预加载懒加载模块
Web Workers 将计算密集型任务移到Web Worker
{{ user.name }}
trackByUserId(index: number, user: User): string {
return user.id;
}
十六、最佳实践
16.1 代码组织
原则 说明
模块化 按功能模块组织代码
单一职责 每个组件/服务只负责一件事
智能展示分离 组件职责清晰
避免any 使用强类型
16.2 命名规范
类型 规范 示例
组件 组件名+Component UserListComponent
服务 名称+Service UserService
管道 名称+Pipe DateFormatPipe
指令 名称+Directive HighlightDirective
类 PascalCase UserService
属性/方法 camelCase userName
常量 UPPER_SNAKE_CASE MAX_COUNT
16.3 常见错误避免
错误 正确做法
内存泄漏 在ngOnDestroy中取消订阅
变更检测性能问题 使用OnPush策略
未处理异步错误 使用catchError处理错误
直接操作DOM 使用ElementRef和Renderer2
总结
本教程系统介绍了Angular开发的各个方面,从基础概念到企业级应用实践。主要内容包括:Angular核心概念和TypeScript基础、组件开发与模板语法、指令系统与服务、路由系统与导航、表单处理(模板驱动与响应式)、HTTP网络请求、状态管理方案(服务+RxJS与NgRx)、RxJS响应式编程、组件生命周期、单元测试、以及性能优化技巧。Angular是一个完整的企业级应用开发平台,特别适合开发大型复杂应用。掌握这些知识后,您可以独立开发功能完整、可维护的Angular应用。