Skip to content

8 Lifecycle Hooks

8.1 Lifecycle Hooks: OnInit Phase

挂载阶段的生命周期函数只在挂载阶段执行一次,数据更新时不再执行。

  1. constructor

Angular 在实例化组件类时执行,可以用来接收 Angular 注入的服务实例对象。

export class ChildComponent {
 constructor (private test: TestService) {
    console.log(this.test) //"test"
  }
}
  1. ngOnInit

在首次接收到输入属性值后执行,在此处可以执行请求操作。

<app-child name="Sam"></app-child>
export class ChildComponent implements OnInit {
 @Input ("name") name: string = ""
  ngOnInit () {
    console. log (this.name) // "Sam"

 }
}
  1. ngAfterContentinit

当内容投影初始渲染完成后调用。

<!-- app-child 组件模板 -->
<p #p>app-child works</p>
export class ChildComponent implements AfterViewInit {
 @ViewChild("p") p: ElementRef<HTMLParagraphElement> | undefined
 ngAfterViewInit () {
     console. log (this.p) // <p>app-child works</p>
 }
}
  1. ngAfterViewInit

当组件视图渲染完成后调用。

<!-- app-child 组件模板-->
<p #p>app-child works</p>
export class ChildComponent implements AfterViewInit {
 @ViewChild("p") p: ElementRef<HTMLParagraphElement> | undefined
  ngAfterViewInit () {
    console. log(this.p) // <p>app-child works</p>
 }
}
import { AfterContentInit, AfterViewInit, Component, OnInit } from '@angular/core';
import { After } from 'v8';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, AfterContentInit, AfterViewInit{

  constructor() { 
    console.log("constructor");
  }

  ngOnInit(): void {
    console.log("ngOnInit");
  }

  ngAfterContentInit(){
    console.log("ngAfterContentInit");
  }

  ngAfterViewInit(){
    console.log("ngAfterViewInit");
  }

}

Screenshot 2025-01-18 at 12.57.36

Screenshot 2025-01-18 at 12.58.08

order: constructor -> ngOnInit -> ngAfterContentInit -> ngAfterViewInit

8.2 Lifecycle Hooks: OnUpdate Phase

ngOnChanges order: ngOnChanges -> ngOnInit -> ngAfterContentInit -> ngAfterViewInit

  1. ngOnChanges
  2. 当输入属性值发生变化时执行,初始设置时也会执行一次,顺序优于 ngOnlnit
  3. 不论多少输入属性同时变化,钩子函数只会执行一次,变化的值会同时存储在参数中
  4. 参数类型为 SimpleChanges,子属性类型为 SimpleChange
  5. 对于基本数据类型来说,只要值发生变化就可以被检测到
  6. 对于引用数据类型来说,可以检测从一个对象变成另一个对象,但是检测不到同一个对象中属性值的变化,但是不影响组件模板更新数据。

基本数据类型值变化

<app-child [name]="name" [age]="age"></app-child>
<button (click)="change ()">change</button>
export class AppComponent {}
    name:string = "张三"
  age: number = 20
    change ( ) {
    this.name = "李四"
    this.age = 30
  }
}
export class ChildComponent implements OnChanges {
  @Input ("name") name: string = ""
  @Input ("age") age: number = 0

  ngonChanges (changes: SimpleChanges) {
        console.log("基本数据类型值变化可以被检测到)
    }
}

app.component.html:

<app-child [name]="name">
    <div #box>Hello Angular</div>
    <!--# 是模板引用变量,可以在组件中通过ViewChild获取-->
</app-child>
<button (click)="change()">Change</button>

app.component.ts:

import { Component } from '@angular/core';


// 组件类 被@Component装饰器装饰
@Component({

  // 制定组件的使用方式, 当前问标记形式
  // app-root => <app-root></app-root> 

  selector: 'app-root', // 当前组件调用的时候你要以什么形式去调用
  templateUrl: './app.component.html', // 当前组件对应的模版是什么 组件模版文件路径
  styleUrls: ['./app.component.css'] // 当前组件对应的样式文件
})

// 导出一个类 
export class AppComponent {
  name: string = 'Sam';
  change(){
    this.name = 'Tom';
  }
}

// selector: '.app-root', // 当前组件调用的时候你要以什么形式去调用
// app-root => <div class="app-root"></div>
// selector: '[app-root]', // 当前组件调用的时候你要以什么形式去调用
// app-root => <div app-root></div>

child.component.ts:

import { AfterContentInit, AfterViewInit, Component, ContentChild, ElementRef, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
import { After } from 'v8';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit, AfterContentInit, AfterViewInit, OnChanges{
  @Input("name") name: string = "";
  @ContentChild("box") box: ElementRef<HTMLDivElement> | undefined;
  @ViewChild("p") p: ElementRef<HTMLParagraphElement> | undefined;
  // @ContentChild => 获取父组件传递的内容 box是父组件传递的内容 HTMLDivElement是父组件传递的内容的类型
  // ElementRef => 获取当前组件的元素
  // @ViewChild => 获取当前组件的内容
  // p是当前组件的内容 HTMLParagraphElement是当前组件的内容的类型

  constructor() { 
    console.log("constructor");
  }

  ngOnInit(): void {
    console.log("ngOnInit");
  }

  ngAfterContentInit(){
    console.log("ngAfterContentInit");
  }

  ngAfterViewInit(){
    console.log("ngAfterViewInit");
  }

  ngOnChanges() {
    console.log("ngOnChanges");
  }

}

child.component.html

<p>child works!</p>
<div> {{name}} </div>

Screenshot 2025-01-18 at 13.28.25

Screenshot 2025-01-18 at 13.28.38

Screenshot 2025-01-18 at 13.28.45

不论多少输入属性同时变化,钩子函数只会执行一次,变化的值会同时存储在参数中

Screenshot 2025-01-18 at 14.02.08

Screenshot 2025-01-18 at 14.02.37

参数类型为 SimpleChanges,子属性类型为 SimpleChange

Screenshot 2025-01-18 at 14.04.01

Screenshot 2025-01-18 at 14.04.20

对于引用数据类型来说,可以检测从一个对象变成另一个对象,但是检测不到同一个对象中属性值的变化,但是不影响组件模板更新数据。

Screenshot 2025-01-18 at 14.11.14

Screenshot 2025-01-18 at 14.11.46

Screenshot 2025-01-18 at 14.11.55

Screenshot 2025-01-18 at 14.12.37

Screenshot 2025-01-18 at 14.12.56

Screenshot 2025-01-18 at 14.13.09

  1. ngDoCheck:主要用于调试,只要输入属性发生变化,不论是基本数据类型还是引用数据类型还是引用数据类型中的属性变化,都会执行。
  2. ngAfterContentChecked:内容投影更新完成后执行。
  3. ngAfterViewChecked:组件视图更新完成后执行。

8.3 Lifecycle Hooks: OnDestroy Phase

  1. ngOnDestroy

当组件被销毁之前调用,用于清理操作。

export class HomeComponent implements OnDestroy {
 ngOnDestroy ( ) {
 console.log"组件被卸载"
}

页面切换

app-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AboutComponent } from './about/about.component';
import { HomeComponent } from './home/home.component';

const routes: Routes = [
  {
    path: '', // 根路径
    component: HomeComponent, // 显示 HomeComponent
    pathMatch: 'full'
  },
  {
    path: 'about', // 显示 AboutComponent
    component: AboutComponent
  }
];


@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

app.component.html

<app-child [person]="person" >
    <div #box>Hello Angular</div>
    <!--# 是模板引用变量,可以在组件中通过ViewChild获取-->
</app-child>
<button (click)="change()">Change</button>
<!-- 页面跳转-->
<p></p>
<!-- app.component.html -->
<nav>
    <a routerLink="/">Home</a>
    <a routerLink="/about">About</a>
</nav>
<router-outlet></router-outlet>

home.component.ts:

import { Component, OnDestroy, OnInit } from '@angular/core';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnDestroy {

  constructor() { }

  ngOnDestroy() {
    console.log('HomeComponent destroyed');
  }

}

Screenshot 2025-01-18 at 14.44.47

Screenshot 2025-01-18 at 14.45.03