[Angular] 查看生命周期方法(ngAfterViewInit 和 ngAfterViewChecked)
首先
在本文中,我们将讨论Angular组件的生命周期,重点关注ngAfterViewInit和ngAfterViewChecked。
更新消息
2021年1月3日
- 記事内で扱ったコードを Angular v11.0.5 で確認しました
工作环境
$ ng --version
Angular$ node --version
npm$ npm --version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | ‘_ \ / _` | | | | |/ _` | ‘__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
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 + '}');
}
}
这段示例代码的目的是什么?
在父组件和子组件中都设置了输入表单。其目的是
-
- 親コンポーネントでビューを変更した際に子コンポーネントで検知するのか
- 逆に子コンポーネントでビューを変更した際に親コンポーネントで検知するのか
为了确认
我要确认执行结果。
打开应用并从日志中确认执行结果。
一开始启动
在启动后的日志中,可以确认以下内容。
-
- 子コンポーネントで ngAfterViewInit -> ngAfterViewChecked の順で実行され (オレンジ色の枠)
- 次に親コンポーネントで ngAfterViewInit -> ngAfterViewChecked の順で実行された (青色の枠)
每个方法的执行顺序
-
- 子コンポーネントの ngAfterViewInit -> 親コンポーネントの ngAfterViewInit の順、
- あるいは子コンポーネントの ngAfterViewChecked -> 親コンポーネントの ngAfterViewChecked の順
而不是关注于该组件内连续执行的点。
这是因为它在初始化视图、检测并执行了变更后,才会转移到下一个组件的处理上。
- コンポーネント単位で Init と Checked が行われる
我明白了。
通过亲子组件的输入进行更新
在父组件的输入表单中输入”通过父组件的输入进行更新”时,下图显示的日志如下(紫色框内)。
然后,在子组件的输入表单中输入”通过父组件的输入进行更新”时,日志如下图所示(在绿色框内)。此时需要先按下F5键重新加载页面,然后进行操作。
从两个日志中可以看出
-
- 子コンポーネントの 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
如果你对这方面很了解的话,我建议你参考一下。
源代码
本次论文中所使用的验证代码已经上传至此处,供参考。。。