Angular-07:组件生命周期

三个阶段:

  • [① 挂载阶段](#① 挂载阶段)
    • [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

  1. 不是组件生命周期函数,是组件类的构造函数,但是他属于挂载阶段
  2. 建议只接收服务实例化对象,不要干其他的事
  3. 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

  1. 输入属性发生变化时执行,初始设置时也会执行一次。响应组件输入值发生变化时出发。(顺序优先于ngOnInit)
  2. 不论有多少个输入属性同时变化,该钩子只会执行一次,变化的值会同时存储在参数中。(多个输入属性一起传递,钩子函数会同时处理)
  3. 参数的类型为SimpleChanges,子属性类型为SimpleChange。
  4. 对于基本数据类型来说,只要值发生改变就可以被该函数检测到。
  5. 对于引用数据类型来说,可以检测从一个对象变成另一个对象(整个对象重新赋值,引用地址发生了变化),但是检测不到同一个对象中属性值的变化(某个属性值被改变),但是不影响组件模板更新数据。(钩子函数捕捉不到改变,但是在组件模板中会变化)

例1:基本数据类型值变化

  1. 给子组件传递一个基本数据类型属性 sonName,值为:王二小。
  2. 定义一个按钮,点击按钮时将该值改为:李四。
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);
  }
  1. 基本数据类型的值改变可以在该方法中被检测到
  2. SimpleChanges对象:包含当前值和变化前的值。输入属性值发生变化时触发。

例2:引用数据类型对象属性变化

  1. 给子组件传递一个对象 sonInfo,值为:{ name: "王二小", age: 18 }。
  2. 定义一个按钮,点击按钮时将该对象的属性改变。
html 复制代码
<!-- 父组件模板 -->

<app-son [sonInfo]="sonInfo"></app-son>
<button (click)="changeInfo()">换个信息</button>

在父组件类中改变该对象的属性

ts 复制代码
// 父组件类

  sonInfo = { name: "王二小", age: 18 };

  changeInfo() {
    this.sonInfo.name = "李四";
    this.sonInfo.age = 3;
  }
  1. 在子组件类中接收该对象sonInfo,并在ngOnChanges中添加打印
ts 复制代码
// 子组件类

 @Input() sonInfo: Object;

  ngOnChanges(changes: SimpleChanges): void {
    console.log("changes", changes);
    console.log("sonInfo", this.sonInfo);
  }

在子组件模板中将该对象显示

html 复制代码
<!-- 子组件模板 -->

<p>{{sonInfo | json}}</p>

最终结果:

  1. 初始化的时候ngOnChanges方法会打印接收的input对象。
  2. 在父组件中点击按钮改变对象属性时,该对象传递到子组件中。
  3. 由于值改变了对象属性,ngOnChanges方法无法检测到该对象的变化,不会输出打印。
  4. 但是在子组件模板中可以看到,该对象已经由最初的 "王二小" 变为了 "李四" 。

例3:引用数据类型引用地址变化

  1. 同例2逻辑,这次在父组件传递给子组件值时改变对象赋值方式。
  2. 在点击按钮时,在父组件中对象重新赋值。(改变对象的引用地址)
ts 复制代码
// 父组件组件类
sonInfo = { name: "王二小", age: 18 };

  changeInfo() {
    this.sonInfo = { name: "李四", age: 3 };
  }

最终结果:

每次点击按钮,ngOnChanges都会检测到该对象的变化


2.2 ngAfterViewInit

  1. 组件视图渲染完成后调用。
  2. angular创建完成组件视图及其子视图之后。

2.3 ngAfterContentInit

  1. 当内容投影初始渲染完成调用。
  2. 组件中使用了将内容嵌入组件视图后会调用,在第一次ngDoCheck执行后调用,且只执行一次。

2.4 ngDoCheck

  1. 用于变化检测,该钩子方法会在每次变化检测发生时调用。
  2. 不管数据值是否发生了变化,都会被调用,该钩子方法需慎用。该方法内不能写复杂代码,会影响性能。
  3. 例如鼠标移动事件,变化检测会频繁触发,该钩子方法会频繁调用。
  4. ngDoCheck和ngOnChange不建议同时使用。

③ 卸载阶段

3.1 onOnDestroy

  1. 什么是卸载?
    组件所对应的dom元素被移除就是卸载。避免发生内存泄漏等问题。
  2. 当组件被销毁之前调用,用于清理操作。
  3. 一个经典应用场景,从a页面b页面时,a页面所对应的组件就会被卸载掉。
  4. 需要在该函数内处理:已订阅的观察者事件清理,定时器清理,绑定的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");
  }

}

执行结果:

相关推荐
无敌喜之郎3 天前
Angular数据绑定详解
前端·javascript·angular·数据绑定
无敌喜之郎4 天前
虚拟滚动 - 从基本实现到 Angular CDK
前端·typescript·angular·虚拟滚动
金木讲编程6 天前
Angular 中 UntypedFormGroup和FormGroup的区别?
angular
无敌喜之郎10 天前
Angular 15 独立组件详解
前端·javascript·angular·独立组件
无敌喜之郎15 天前
Angular 控制流与延迟视图揭秘
typescript·angular·1024程序员节
余生H19 天前
JS异步编程进阶(二):rxjs与Vue、React、Angular框架集成及跨框架状态管理实现原理
javascript·vue.js·react.js·angular·rxjs·异步编程
职教育人22 天前
前端三大框架对比与选择
前端·vue.js·react·angular
优联前端23 天前
前端框架对比和选择
前端框架·vue·react·angular·优联前端
无敌喜之郎24 天前
Angular signal信号详细解析
前端·typescript·angular·signal
zqwang88824 天前
Angular 实现 keep-alive (路由复用)
前端·angular·angular.js