[Angular] 查看生命周期方法(ngAfterViewInit 和 ngAfterViewChecked)

首先

在本文中,我们将讨论Angular组件的生命周期,重点关注ngAfterViewInit和ngAfterViewChecked。

更新消息

2021年1月3日

    記事内で扱ったコードを Angular v11.0.5 で確認しました

工作环境

環境バージョン備考Angular CLIv1.6.3 v11.0.5$ ng --versionAngularv4.4.6 v11.0.5同上TypeScriptv4.0.2同上Node.jsv9.2.1 v12.18.3$ node --versionnpmv5.6.0 v6.14.6$ npm --version
ng 版本的结果$ ng 版本

_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | ‘_ \ / _` | | | | |/ _` | ‘__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/

Angular CLI:11.0.5
Node:12.18.3
操作系统:darwin x64

Angular:11.0.5
…动画,cli,公共,编译器,编译器-cli,核心,表单
…平台浏览器,平台浏览器动态,路由器
Ivy 工作区:是的

包 版本
———————————————————-
@angular-devkit/architect 0.1100.5
@angular-devkit/build-angular 0.1100.5
@angular-devkit/core 11.0.5
@angular-devkit/schematics 11.0.5
@schematics/angular 11.0.5
@schematics/update 0.1100.5
rxjs 6.6.0
typescript 4.0.2

相关文章

    • [Angular] ライフサイクルメソッドをみる(ngOnChanges と ngOnInit と ngOnDestroy)

 

    • [Angular] ライフサイクルメソッドをみる(ngDoCheck)

 

    • [Angular] ライフサイクルメソッドをみる(ngAfterContentInit と ngAfterContentChecked)

 

    [Angular] 子コンポーネントや外部コンテンツの参照を取得する

ngAfterViewInit 和 ngAfterViewChecked

这些方法很容易根据方法名推断出来。换句话说,它们在视图的初始化和变化时执行。

    • ngAfterViewInit は ビューの初期化後に一度だけ

ngAfterViewChecked は ビューが変更される度 に

下面的代码中分别运行验证。
接下来,通过实际代码进行确认。

根组件

只需在这里简单地注册本次确认对象的组件。

<!-- 親コンポーネントを登録 -->
<app-view-parent>
</app-view-parent>

父母组件

在称为view-parent.component的父组件中

    • 入力フォームの設置

 

    • テンプレートで子コンポーネントを登録

 

    クラスでは子コンポーネントへの参照を取得して ngAfterViewChecked で更新

进行。

<p>
  親コンポーネントの入力フォームからビューの変更を確認する
</p>

<label for="inputText">入力項目(親):</label>
<input id="inputText" name="inputText" type="text" [(ngModel)]="ngAfterViewCheckValue" />

<!-- 子コンポーネントを登録 -->
<app-view-child>
</app-view-child>
import { Component, OnInit } from '@angular/core';

// ngAferViewInit と ngAfterViewChecked を利用するための import
import { AfterViewInit, AfterViewChecked } from '@angular/core';

// 子コンポーネントで定義されたプロパティを取得するための import
import { ViewChild } from '@angular/core';

// 子コンポーネントを import
import { ViewChildComponent} from '../view-child/view-child.component';

@Component({
  selector: 'app-view-parent',
  templateUrl: './view-parent.component.html',
  styleUrls: ['./view-parent.component.css']
})
export class ViewParentComponent implements OnInit, AfterViewInit, AfterViewChecked {

  /**
   * ngAfterViewInit と ngAfterViewChecked の確認のためのプロパティ
   *
   * @type {String}
   * @memberof ViewChildComponent
   */
  public ngAfterViewCheckValue: String = '';

  /**
   * 子コンポーネントを参照
   *
   * @type {ViewChildComponent}
   * @memberof ViewParentComponent
   */
  @ViewChild(ViewChildComponent) viewChild!: ViewChildComponent;

  constructor() { }

  /**
   * コンポーネントの初期化処理
   *
   * @memberof ViewParentComponent
   */
  ngOnInit() {
    this.ngAfterViewCheckValue = 'ngOnInitで初期化した';
  }

  /**
   * ビューの初期化をフックする
   *
   * @memberof ViewParentComponent
   */
  ngAfterViewInit() {
    console.log('[ViewParentComponent][ngAfterViewInit] fired');
  }

  /**
   * ビューの変更をフックする
   *
   * @memberof ViewParentComponent
   */
  ngAfterViewChecked() {
    console.log('[ViewParentComponent][ngAfterViewChecked] fired. ngAfterViewCheckValue={' + this.ngAfterViewCheckValue + '}');
  }
}

子组件

在子组件view-child.component中展示了

    入力フォームの設置

进行。

<p>
  子コンポーネントの入力フォームからビューの変更を確認する
</p>

<label for="inputText">入力項目(子):</label>
<input id="inputText" name="inputText" type="text" [(ngModel)]="ngAfterViewCheckValue" />
import { Component, OnInit } from '@angular/core';

// ngAferViewInit と ngAfterViewChecked を利用するための import
import { AfterViewInit, AfterViewChecked } from '@angular/core';

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

  /**
   * ngAfterViewInit と ngAfterViewChecked の確認のためのプロパティ
   *
   * @type {String}
   * @memberof ViewChildComponent
   */
  public ngAfterViewCheckValue: String = '';

  constructor() { }

  /**
   * コンポーネントの初期化処理
   *
   * @memberof ViewChildComponent
   */
  ngOnInit() {
    this.ngAfterViewCheckValue = 'ngOnInitで初期化した';
  }

  /**
   * ビューの初期化をフックする
   *
   * @memberof ViewChildComponent
   */
  ngAfterViewInit() {
    console.log('[ViewChildComponent][ngAfterViewInit] fired.');
  }

  /**
   * ビューの変更をフックする
   *
   * @memberof ViewChildComponent
   */
  ngAfterViewChecked() {
    console.log('[ViewChildComponent][ngAfterViewChecked] fired. ngAfterViewCheckValue={' + this.ngAfterViewCheckValue + '}');
  }
}

这段示例代码的目的是什么?

在父组件和子组件中都设置了输入表单。其目的是

    • 親コンポーネントでビューを変更した際に子コンポーネントで検知するのか

 

    逆に子コンポーネントでビューを変更した際に親コンポーネントで検知するのか

为了确认

我要确认执行结果。

打开应用并从日志中确认执行结果。

一开始启动

ngAfterView-boot.png

在启动后的日志中,可以确认以下内容。

    • 子コンポーネントで ngAfterViewInit -> ngAfterViewChecked の順で実行され (オレンジ色の枠)

 

    次に親コンポーネントで ngAfterViewInit -> ngAfterViewChecked の順で実行された (青色の枠)

每个方法的执行顺序

    • 子コンポーネントの ngAfterViewInit -> 親コンポーネントの ngAfterViewInit の順、

 

    あるいは子コンポーネントの ngAfterViewChecked -> 親コンポーネントの ngAfterViewChecked の順

而不是关注于该组件内连续执行的点。
这是因为它在初始化视图、检测并执行了变更后,才会转移到下一个组件的处理上。

    コンポーネント単位で Init と Checked が行われる

我明白了。

通过亲子组件的输入进行更新

在父组件的输入表单中输入”通过父组件的输入进行更新”时,下图显示的日志如下(紫色框内)。

ngAfterView-input-parent.png

然后,在子组件的输入表单中输入”通过父组件的输入进行更新”时,日志如下图所示(在绿色框内)。此时需要先按下F5键重新加载页面,然后进行操作。

ngAfterView-input-child.png

从两个日志中可以看出

    • 子コンポーネントの ngAfterViewChecked が実行され

 

    次に親コンポーネント ngAfterViewChecked が実行された

可以确认这一点。同时无论在父组件还是子组件中输入都可以。

    親コンポーネントの ngAfterViewChecked と 子コンポーネントの ngAfterViewChecked が実行された

可以确认这一点。值得注意的是,由于 ngAfterViewInit 只在应用程序启动后执行一次,因此在进行此操作时只执行了 ngAfterViewChecked。

注意力集中在

(zhù mù jué

    親コンポーネントと子コンポーネントの両方の ngAfterViewChecked が実行

如果从这一点出发,对视图进行了更改的话,

コンポーネント単位の変更ではなくそのページ全体の変更として検知されていること
また ngAfterViewChecked を実装したコンポーネント全てで変更をフックしている

能够理解这件事。

总结一下

虽然重复了在执行结果确认中所写的内容,但我们可以确认以下事项。

    • ngAfterViewInit と ngAfterViewChecked はコンポーネント単位で Init と Checked が行われること

 

    • ビューの変更が行われたらコンポーネント単位の変更ではなくそのページ全体の変更として検知されていること

ngAfterViewChecked を実装したコンポーネント全てで変更をフックしていること

对于在上述相关文章中看到的生命周期方法,同样可以说,当组件或视图发生初始化或更改时,生命周期方法会钩取并执行相应的处理。在这种情况下,Angular 不关心“在哪个组件上进行了初始化或更新”,而是只关心“简单地进行了初始化或更新”。

这意味着,生命周期方法并不仅仅需要在所有组件中实现,而是需要理解每个生命周期方法的特点,并在确定需要的情况和位置时使用。

特别是在每次检测到变化时,例如ngOnChanges、ngDoCheck、ngAfterContentChecked和ngAfterViewChecked等方法都会被执行,如果在所有组件中都无脑实现这些方法,那么执行次数将变得非常庞大。所以需要非常注意。

填补

在ngAfterViewInit或ngAfterViewChecked中,当尝试更新与视图相关的属性时,会发生以下错误。

错误错误:ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后发生了改变。

对于这个避免措施

    https://qiita.com/tomonari-t/items/3fd6d3c30b6b007b0f14

如果你对这方面很了解的话,我建议你参考一下。

源代码

本次论文中所使用的验证代码已经上传至此处,供参考。。。

广告
将在 10 秒后关闭
bannerAds