组件生命周期 #
一、生命周期概述 #
Angular组件从创建到销毁会经历一系列阶段,每个阶段都有对应的钩子函数。
text
┌─────────────────────────────────────────────────────────────┐
│ 组件生命周期 │
├─────────────────────────────────────────────────────────────┤
│ 创建阶段 │
│ ├── constructor() 构造函数 │
│ ├── ngOnChanges() 输入属性变化 │
│ └── ngOnInit() 初始化 │
│ │
│ 更新阶段 │
│ ├── ngDoCheck() 变更检测 │
│ ├── ngOnChanges() 输入属性变化 │
│ └── ngAfterContentChecked() 内容变更检测 │
│ │
│ 视图阶段 │
│ ├── ngAfterContentInit() 内容初始化 │
│ ├── ngAfterViewInit() 视图初始化 │
│ └── ngAfterViewChecked() 视图变更检测 │
│ │
│ 销毁阶段 │
│ └── ngOnDestroy() 组件销毁 │
└─────────────────────────────────────────────────────────────┘
二、生命周期执行顺序 #
text
constructor()
↓
ngOnChanges() (如果有@Input属性)
↓
ngOnInit()
↓
ngDoCheck()
↓
ngAfterContentInit()
↓
ngAfterContentChecked()
↓
ngAfterViewInit()
↓
ngAfterViewChecked()
↓
(变更检测循环)
↓
ngOnDestroy()
三、constructor构造函数 #
3.1 基本用法 #
typescript
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
template: '<p>Example</p>'
})
export class ExampleComponent {
name: string;
constructor() {
this.name = 'Angular';
console.log('constructor执行');
}
}
3.2 依赖注入 #
typescript
@Component({
selector: 'app-user',
template: '<p>{{ user.name }}</p>'
})
export class UserComponent {
user: User;
constructor(
private userService: UserService,
private route: ActivatedRoute
) {
console.log('constructor: 依赖注入完成');
}
}
3.3 constructor vs ngOnInit #
| constructor | ngOnInit |
|---|---|
| TypeScript特性 | Angular特性 |
| 用于依赖注入 | 用于初始化逻辑 |
| 输入属性未绑定 | 输入属性已绑定 |
| 不应包含复杂逻辑 | 可包含初始化逻辑 |
四、ngOnChanges #
4.1 基本用法 #
typescript
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-child',
template: '<p>{{ name }}</p>'
})
export class ChildComponent implements OnChanges {
@Input() name: string = '';
@Input() age: number = 0;
ngOnChanges(changes: SimpleChanges) {
console.log('ngOnChanges:', changes);
if (changes['name']) {
const prevName = changes['name'].previousValue;
const currentName = changes['name'].currentValue;
const isFirstChange = changes['name'].firstChange;
console.log(`name: ${prevName} → ${currentName}`);
}
if (changes['age']) {
console.log(`age: ${changes['age'].previousValue} → ${changes['age'].currentValue}`);
}
}
}
4.2 SimpleChanges对象 #
typescript
interface SimpleChange {
previousValue: any; // 之前的值
currentValue: any; // 当前的值
firstChange: boolean; // 是否首次变化
}
// changes对象结构
{
name: {
previousValue: 'John',
currentValue: 'Jane',
firstChange: false
},
age: {
previousValue: 25,
currentValue: 26,
firstChange: false
}
}
4.3 使用场景 #
typescript
@Component({
selector: 'app-user-detail',
template: `
<div *ngIf="user">
<h3>{{ user.name }}</h3>
<p>{{ formattedInfo }}</p>
</div>
`
})
export class UserDetailComponent implements OnChanges {
@Input() user: User;
formattedInfo: string;
ngOnChanges(changes: SimpleChanges) {
if (changes['user'] && this.user) {
this.formattedInfo = this.formatUserInfo(this.user);
}
}
private formatUserInfo(user: User): string {
return `${user.name}, ${user.age}岁, ${user.email}`;
}
}
五、ngOnInit #
5.1 基本用法 #
typescript
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-user',
template: '<p>{{ user.name }}</p>'
})
export class UserComponent implements OnInit {
user: User;
constructor(private userService: UserService) {}
ngOnInit() {
this.loadUser();
}
private loadUser() {
this.userService.getUser().subscribe(user => {
this.user = user;
});
}
}
5.2 初始化逻辑 #
typescript
@Component({
selector: 'app-product',
template: `
<div *ngFor="let product of products">
{{ product.name }}
</div>
`
})
export class ProductComponent implements OnInit {
products: Product[] = [];
constructor(
private productService: ProductService,
private route: ActivatedRoute
) {}
ngOnInit() {
this.route.params.subscribe(params => {
const categoryId = params['id'];
this.loadProducts(categoryId);
});
}
private loadProducts(categoryId: number) {
this.productService.getProducts(categoryId)
.subscribe(products => {
this.products = products;
});
}
}
5.3 ngOnInit最佳实践 #
typescript
@Component({
selector: 'app-example',
template: '...'
})
export class ExampleComponent implements OnInit {
private destroy$ = new Subject<void>();
constructor(private service: DataService) {}
ngOnInit() {
this.service.getData()
.pipe(takeUntil(this.destroy$))
.subscribe(data => {
console.log(data);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
六、ngDoCheck #
6.1 基本用法 #
typescript
import { Component, DoCheck } from '@angular/core';
@Component({
selector: 'app-example',
template: '<p>{{ message }}</p>'
})
export class ExampleComponent implements DoCheck {
message = 'Hello';
ngDoCheck() {
console.log('ngDoCheck: 变更检测执行');
}
}
6.2 自定义变更检测 #
typescript
@Component({
selector: 'app-list',
template: `
<p>列表长度: {{ items.length }}</p>
<p>总价格: {{ totalPrice }}</p>
`
})
export class ListComponent implements DoCheck {
@Input() items: Item[] = [];
totalPrice: number = 0;
private previousLength: number = 0;
ngDoCheck() {
if (this.items.length !== this.previousLength) {
this.previousLength = this.items.length;
this.calculateTotal();
}
}
private calculateTotal() {
this.totalPrice = this.items.reduce((sum, item) => sum + item.price, 0);
}
}
七、内容投影钩子 #
7.1 ngAfterContentInit #
typescript
import { Component, ContentChild, AfterContentInit } from '@angular/core';
@Component({
selector: 'app-wrapper',
template: `
<div class="wrapper">
<ng-content></ng-content>
</div>
`
})
export class WrapperComponent implements AfterContentInit {
@ContentChild('header') header;
ngAfterContentInit() {
console.log('内容投影初始化完成');
console.log('header:', this.header);
}
}
7.2 ngAfterContentChecked #
typescript
@Component({
selector: 'app-wrapper',
template: `
<div class="wrapper">
<ng-content></ng-content>
</div>
`
})
export class WrapperComponent implements AfterContentChecked {
ngAfterContentChecked() {
console.log('内容变更检测完成');
}
}
八、视图钩子 #
8.1 ngAfterViewInit #
typescript
import { Component, ViewChild, AfterViewInit, ElementRef } from '@angular/core';
@Component({
selector: 'app-example',
template: `
<input #input type="text" />
<app-child #child></app-child>
`
})
export class ExampleComponent implements AfterViewInit {
@ViewChild('input') inputElement: ElementRef;
@ViewChild('child') childComponent: ChildComponent;
ngAfterViewInit() {
console.log('视图初始化完成');
this.inputElement.nativeElement.focus();
console.log('子组件:', this.childComponent);
}
}
8.2 ngAfterViewChecked #
typescript
@Component({
selector: 'app-example',
template: `
<p>{{ message }}</p>
<app-child></app-child>
`
})
export class ExampleComponent implements AfterViewChecked {
message = 'Hello';
ngAfterViewChecked() {
console.log('视图变更检测完成');
}
}
8.3 视图更新注意事项 #
typescript
@Component({
selector: 'app-example',
template: '<p>{{ message }}</p>'
})
export class ExampleComponent implements AfterViewChecked {
message = 'Hello';
ngAfterViewChecked() {
// 错误:会导致无限循环
// this.message = 'Updated';
// 正确:使用setTimeout
// setTimeout(() => {
// this.message = 'Updated';
// });
}
}
九、ngOnDestroy #
9.1 基本用法 #
typescript
import { Component, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-example',
template: '<p>Example</p>'
})
export class ExampleComponent implements OnDestroy {
private subscription: Subscription;
constructor(private service: DataService) {
this.subscription = this.service.getData().subscribe();
}
ngOnDestroy() {
console.log('组件销毁');
this.subscription.unsubscribe();
}
}
9.2 清理资源 #
typescript
@Component({
selector: 'app-timer',
template: '<p>{{ count }}</p>'
})
export class TimerComponent implements OnInit, OnDestroy {
count = 0;
private timer: any;
ngOnInit() {
this.timer = setInterval(() => {
this.count++;
}, 1000);
}
ngOnDestroy() {
if (this.timer) {
clearInterval(this.timer);
}
}
}
9.3 使用takeUntil模式 #
typescript
import { Component, OnDestroy } from '@angular/core';
import { Subject, takeUntil } from 'rxjs';
@Component({
selector: 'app-example',
template: '...'
})
export class ExampleComponent implements OnDestroy {
private destroy$ = new Subject<void>();
constructor(
private userService: UserService,
private dataService: DataService
) {
this.userService.getUser()
.pipe(takeUntil(this.destroy$))
.subscribe(user => {
console.log(user);
});
this.dataService.getData()
.pipe(takeUntil(this.destroy$))
.subscribe(data => {
console.log(data);
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
十、生命周期完整示例 #
typescript
import {
Component,
Input,
OnInit,
OnChanges,
DoCheck,
AfterContentInit,
AfterContentChecked,
AfterViewInit,
AfterViewChecked,
OnDestroy,
SimpleChanges
} from '@angular/core';
@Component({
selector: 'app-lifecycle',
template: `
<div class="lifecycle">
<h3>Lifecycle Demo</h3>
<p>计数: {{ count }}</p>
<button (click)="increment()">+1</button>
</div>
`
})
export class LifecycleComponent implements
OnInit,
OnChanges,
DoCheck,
AfterContentInit,
AfterContentChecked,
AfterViewInit,
AfterViewChecked,
OnDestroy {
@Input() initialCount: number = 0;
count: number = 0;
constructor() {
console.log('1. constructor');
}
ngOnChanges(changes: SimpleChanges) {
console.log('2. ngOnChanges', changes);
if (changes['initialCount']) {
this.count = this.initialCount;
}
}
ngOnInit() {
console.log('3. ngOnInit');
}
ngDoCheck() {
console.log('4. ngDoCheck');
}
ngAfterContentInit() {
console.log('5. ngAfterContentInit');
}
ngAfterContentChecked() {
console.log('6. ngAfterContentChecked');
}
ngAfterViewInit() {
console.log('7. ngAfterViewInit');
}
ngAfterViewChecked() {
console.log('8. ngAfterViewChecked');
}
ngOnDestroy() {
console.log('9. ngOnDestroy');
}
increment() {
this.count++;
}
}
十一、生命周期使用场景 #
| 钩子 | 使用场景 |
|---|---|
constructor |
依赖注入、简单初始化 |
ngOnChanges |
响应输入属性变化 |
ngOnInit |
复杂初始化、获取数据 |
ngDoCheck |
自定义变更检测 |
ngAfterContentInit |
访问投影内容 |
ngAfterViewInit |
访问视图、DOM操作 |
ngOnDestroy |
清理资源、取消订阅 |
十二、总结 #
| 钩子 | 执行次数 | 说明 |
|---|---|---|
| constructor | 1次 | 构造函数 |
| ngOnChanges | 多次 | 输入属性变化时 |
| ngOnInit | 1次 | 初始化 |
| ngDoCheck | 多次 | 每次变更检测 |
| ngAfterContentInit | 1次 | 内容初始化 |
| ngAfterContentChecked | 多次 | 内容变更检测 |
| ngAfterViewInit | 1次 | 视图初始化 |
| ngAfterViewChecked | 多次 | 视图变更检测 |
| ngOnDestroy | 1次 | 组件销毁 |
下一步:内置指令
最后更新:2026-03-26