三个阶段:
- [① 挂载阶段](#① 挂载阶段)
-
- [1.1 constructor](#1.1 constructor)
- [1.2 ngOnInit](#1.2 ngOnInit)
- [② 更新阶段](#② 更新阶段)
-
- [2.1 ngOnChanges](#2.1 ngOnChanges)
- [2.2 ngAfterViewInit](#2.2 ngAfterViewInit)
- [2.3 ngAfterContentInit](#2.3 ngAfterContentInit)
- [2.4 ngDoCheck](#2.4 ngDoCheck)
- [③ 卸载阶段](#③ 卸载阶段)
-
- [3.1 onOnDestroy](#3.1 onOnDestroy)
- [④ 在组件中添加所有方法并打印](#④ 在组件中添加所有方法并打印)
该表按照执行顺序编写
编号 | 函数名 | 实现名 | 说明 |
---|---|---|---|
1 | constructor | constructor | 接收服务实例化对象 |
2 | ngOnChanges | OnChanges | 当输入属性值发生变化时执行 |
3 | ngOnInit | OnInit | 在首次接收到输入属性值后执行 |
4 | ngDoCheck | DoCheck | 主要用于调试,每次变化检测发生时调用 |
5 | ngAfterContentInit | AfterContentInit | 当内容投影初始渲染完成后调用 |
6 | ngAfterContentChecked | AfterContentChecked | 内容投影更新完成后执行 |
7 | ngAfterViewInit | AfterViewInit | 当组件视图渲染完成后调用 |
8 | ngAfterViewChecked | AfterViewChecked | 组件视图更新完成后执行 |
9 | ngOnDestroy | OnDestroy | 组件被销毁之前调用 |
① 挂载阶段
该阶段生命周期函数只执行一次,数据更新时不再执行。
1.1 constructor
- 不是组件生命周期函数,是组件类的构造函数,但是他属于挂载阶段
- 建议只接收服务实例化对象,不要干其他的事
- angular实例化组件类时执行,可以用来接收angular注入的服务实例对象。
例: 创建一个服务"TestService", 在组件中注入服务并在constructor中打印查看结果
TestService:
ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class TestService {
testTip = "test,来自服务的消息";
constructor() { }
}
ts
export class OtherComponent implements OnInit{
constructor(
private TestService: TestService
) {
console.log("this.TestService--", this.TestService.testTip); // test,来自服务的消息
}
}
结果:
1.2 ngOnInit
在首次接收到输入属性后执行,也用来做初始化任务执行
例: 创建一个子组件,在父组件中传递给子组件一个输入值,在子组件中打印查看结果。
在父组件中的子组件标签定义好属性
html
<!-- 父组件模板 -->
<app-son [sonName]="'王二小'"></app-son>
子组件接收该属性值并打印
ts
// 子组件类
export class SonComponent implements OnInit {
@Input() sonName: string = '';
constructor() { }
ngOnInit() {
console.log("sonName", this.sonName); // 王二小
}
}
结果:
② 更新阶段
2.1 ngOnChanges
- 输入属性发生变化时执行,初始设置时也会执行一次。响应组件输入值发生变化时出发。(顺序优先于ngOnInit)
- 不论有多少个输入属性同时变化,该钩子只会执行一次,变化的值会同时存储在参数中。(多个输入属性一起传递,钩子函数会同时处理)
- 参数的类型为SimpleChanges,子属性类型为SimpleChange。
- 对于基本数据类型来说,只要值发生改变就可以被该函数检测到。
- 对于引用数据类型来说,可以检测从一个对象变成另一个对象(整个对象重新赋值,引用地址发生了变化),但是检测不到同一个对象中属性值的变化(某个属性值被改变),但是不影响组件模板更新数据。(钩子函数捕捉不到改变,但是在组件模板中会变化)
例1:基本数据类型值变化
- 给子组件传递一个基本数据类型属性 sonName,值为:王二小。
- 定义一个按钮,点击按钮时将该值改为:李四。
html
<!-- 父组件 -->
<app-son [sonName]="sonName"></app-son>
<button (click)="changeName()">换个名字</button>
ts
// 父组件类
sonName: string = '王二小';
changeName() {
this.sonName = "李四";
}
在子组件类中接收该值,并在ngOnChanges方法中添加打印,查看该值的变化
ts
// 子组件类
@Input() sonName: string;
ngOnChanges(changes: SimpleChanges): void {
console.log("changes", changes);
console.log("sonName", this.sonName);
}
- 基本数据类型的值改变可以在该方法中被检测到
- SimpleChanges对象:包含当前值和变化前的值。输入属性值发生变化时触发。
例2:引用数据类型对象属性变化
- 给子组件传递一个对象 sonInfo,值为:{ name: "王二小", age: 18 }。
- 定义一个按钮,点击按钮时将该对象的属性改变。
html
<!-- 父组件模板 -->
<app-son [sonInfo]="sonInfo"></app-son>
<button (click)="changeInfo()">换个信息</button>
在父组件类中改变该对象的属性
ts
// 父组件类
sonInfo = { name: "王二小", age: 18 };
changeInfo() {
this.sonInfo.name = "李四";
this.sonInfo.age = 3;
}
- 在子组件类中接收该对象sonInfo,并在ngOnChanges中添加打印
ts
// 子组件类
@Input() sonInfo: Object;
ngOnChanges(changes: SimpleChanges): void {
console.log("changes", changes);
console.log("sonInfo", this.sonInfo);
}
在子组件模板中将该对象显示
html
<!-- 子组件模板 -->
<p>{{sonInfo | json}}</p>
最终结果:
- 初始化的时候ngOnChanges方法会打印接收的input对象。
- 在父组件中点击按钮改变对象属性时,该对象传递到子组件中。
- 由于值改变了对象属性,ngOnChanges方法无法检测到该对象的变化,不会输出打印。
- 但是在子组件模板中可以看到,该对象已经由最初的 "王二小" 变为了 "李四" 。
例3:引用数据类型引用地址变化
- 同例2逻辑,这次在父组件传递给子组件值时改变对象赋值方式。
- 在点击按钮时,在父组件中对象重新赋值。(改变对象的引用地址)
ts
// 父组件组件类
sonInfo = { name: "王二小", age: 18 };
changeInfo() {
this.sonInfo = { name: "李四", age: 3 };
}
最终结果:
每次点击按钮,ngOnChanges都会检测到该对象的变化
2.2 ngAfterViewInit
- 组件视图渲染完成后调用。
- angular创建完成组件视图及其子视图之后。
2.3 ngAfterContentInit
- 当内容投影初始渲染完成调用。
- 组件中使用了将内容嵌入组件视图后会调用,在第一次ngDoCheck执行后调用,且只执行一次。
2.4 ngDoCheck
- 用于变化检测,该钩子方法会在每次变化检测发生时调用。
- 不管数据值是否发生了变化,都会被调用,该钩子方法需慎用。该方法内不能写复杂代码,会影响性能。
- 例如鼠标移动事件,变化检测会频繁触发,该钩子方法会频繁调用。
- ngDoCheck和ngOnChange不建议同时使用。
③ 卸载阶段
3.1 onOnDestroy
- 什么是卸载?
组件所对应的dom元素被移除就是卸载。避免发生内存泄漏等问题。 - 当组件被销毁之前调用,用于清理操作。
- 一个经典应用场景,从a页面b页面时,a页面所对应的组件就会被卸载掉。
- 需要在该函数内处理:已订阅的观察者事件清理,定时器清理,绑定的dom清理(一些不会被垃圾回收器自动回收的资源)
④ 在组件中添加所有方法并打印
在组件中,所有方法的无序的排列(未按照执行顺序排列)。因为每个方法有自己的特有的执行条件,并非按照先后顺序执行。
ts
@Component({
selector: 'app-son',
templateUrl: './son.component.html',
styleUrls: ['./son.component.css']
})
export class SonComponent implements OnInit, AfterViewInit, AfterContentInit, OnChanges, DoCheck, AfterContentChecked, AfterViewChecked, OnDestroy {
constructor() {
console.log("constructor");
}
ngAfterViewChecked(): void {
console.log("ngAfterViewChecked");
}
ngOnDestroy(): void {
console.log("ngOnDestroy");
}
ngAfterContentChecked(): void {
console.log("ngAfterContentChecked");
}
ngDoCheck(): void {
console.log("ngDoCheck");
}
ngOnChanges(changes: SimpleChanges): void {
console.log("ngOnChanges");
}
ngAfterContentInit(): void {
console.log("ngAfterContentInit");
}
ngOnInit() {
console.log("ngOnInit");
}
ngAfterViewInit(): void {
console.log("ngAfterViewInit");
}
}
执行结果: