Angular 个人深究(四)【生命周期钩子】

Angular 个人深究(四)【生命周期钩子】

定义:

每个组件都有一个被 Angular 管理的生命周期。

Angular 创建它,渲染它,创建并渲染它的子组件,在它被绑定的属性发生变化时检查它,并在它从 DOM 中被移除前销毁它。

Angular 提供了生命周期钩子,把这些关键生命时刻暴露出来,赋予你在它们发生时采取行动的能力。

除了那些组件内容和视图相关的钩子外,指令有相同生命周期钩子。

概览:

 ngOnChanges() 

当 Angular(重新)设置数据绑定输入属性时响应。 该方法接受当前和上一属性值的 SimpleChanges 对象

当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在 ngOnInit() 之前。

 ngOnInit() 

在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。

在第一轮 ngOnChanges() 完成之后调用,只调用一次。

 ngDoCheck() 

检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。

在每个 Angular 变更检测周期中调用,ngOnChanges() 和 ngOnInit()之后。

 ngAfterContentInit() 

当把内容投影进组件之后调用。

第一次 ngDoCheck() 之后调用,只调用一次。

 ngAfterContentChecked() 

每次完成被投影组件内容的变更检测之后调用。

ngAfterContentInit() 和每次 ngDoCheck() 之后调用

 ngAfterViewInit() 

初始化完组件视图及其子视图之后调用。

第一次 ngAfterContentChecked() 之后调用,只调用一次。

 ngAfterViewChecked() 

每次做完组件视图和子视图的变更检测之后调用。

ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。

 ngOnDestroy() 

当 Angular 每次销毁指令/组件之前调用并清扫。 在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。

在 Angular 销毁指令/组件之前调用。

范例:

  ngOnChanges()、ngInit

test2.component.ts

// test2.component.ts:

import { Component, OnInit,Input } from '@angular/core'; @Component({selector: 'app-test2',templateUrl: './test2.component.html',styleUrls: ['./test2.component.css'] })
//需要继承 OnInit、OnChanges 接口 export class Test2Component implements OnInit OnChanges{
// 两个input 来自 父组件 test1@Input() test2_value1: string;@Input() test2_value2: string;constructor() { }ngOnInit() {
          //判断 ngOnInit的执行顺序console.log("这里执行ngOnInit");}ngOnChanges(changes:SimpleChanges){console.log(changes);for (let propName in changes) {let chng = changes[propName];let cur = JSON.stringify(chng.currentValue);let prev = JSON.stringify(chng.previousValue);console.log(`${propName}: 新值 = ${cur}, 旧值 = ${prev}`);}} }

 test1.component.html

<!-- test1.component.html -->
<p>test1 works!
</p>
<label> test1 value</label>
<input  type="text" [(ngModel)]="test1_value1" >
<input  type="text" [(ngModel)]="test1_value2" >
<!-- 将test1_value1的值给test2_value1... -->
<app-test2 [test2_value1]="test1_value1" [test2_value2]="test1_value2"></app-test2>

结果:

 

说明:

  • 刚刷新页面时,将test2_value1、test2_value2的值 从 undefined 变成 1、2。
  • 页面更改test1_value1,将test2_value1的值  从  1 变成  11。
  • 以此类推, 可以使用 ngOnChanges对值发生变化时进行处理。
  • ngInit 的执行顺序在 ngOnChanges之后,可以做一下初始化的工作

 

  ngDoCheck()

test2.component.ts

import { Component, OnInit,Input,OnChanges,DoCheck} from '@angular/core';
@Component({selector: 'app-test2',templateUrl: './test2.component.html',styleUrls: ['./test2.component.css']
})
//需要实现 DoCheck 接口 export class Test2Component implements OnInit OnChanges DoCheck{@Input() test2_value1: string;@Input() test2_value2: string;constructor() { }ngOnInit() {//console.log("这里执行ngOnInit");}ngOnChanges(changes:SimpleChanges){//console.log(changes);for (let propName in changes) {let chng = changes[propName];let cur = JSON.stringify(chng.currentValue);let prev = JSON.stringify(chng.previousValue);//console.log(`${propName}: 新值 = ${cur}, 旧值 = ${prev}`);}}ngDoCheck(){console.log("执行ngDoCheck");} }  

结果:

说明:

  • 刷新页面的时候,执行了两次。
  • 每次鼠标放到,input框上就会执行一次
  • 更改input值,也会执行一次,开销非常大。慎用!

  ngAfterContentInit()

app.component.ts

import { Component } from '@angular/core';@Component({selector: 'app-root',//templateUrl: './app.component.html',//在app主组价中,将test2组件放到test1组件中,template: `<app-test1><app-test2></app-test2></app-test1>`,styleUrls: ['./app.component.css']
})
export class AppComponent {title = 'app';
}

test1.component.ts

import { Component, OnInit,OnChanges} from '@angular/core';@Component({selector: 'app-test1',//templateUrl: './test1.component.html',//ng-content指定的是外来的组件 在组件app中定义的 test2组件//同样在test1组件中,也增加test2 组件 template: `<div> <ng-content></ng-content> <app-test2></app-test2> </div>`,styleUrls: ['./test1.component.css']
})
export class Test1Component implements OnInit, OnChanges{test1_value1:string;test1_value2:string;constructor() { }ngOnInit() {this.test1_value1="1"this.test1_value2="2"}ngOnChanges(){console.log("onchange");}
}

test2.component.ts

import { Component, OnInit,Input ,OnChanges,DoCheck,SimpleChanges,AfterContentInit} from '@angular/core';
@Component({selector: 'app-test2',templateUrl: './test2.component.html',styleUrls: ['./test2.component.css']
})
export class Test2Component implements OnInit,OnChanges,DoCheck,AfterContentInit{@Input() test2_value1: string;@Input() test2_value2: string;constructor() { }ngOnInit() {//console.log("这里执行ngOnInit");
    }ngOnChanges(changes:SimpleChanges){//console.log(changes);for (let propName in changes) {let chng = changes[propName];let cur  = JSON.stringify(chng.currentValue);let prev = JSON.stringify(chng.previousValue);//console.log(`${propName}: 新值 = ${cur}, 旧值 = ${prev}`);
        }}ngDoCheck(){console.log("执行ngDoCheck");}ngAfterContentInit(){console.log("执行ngAfterContentInit");}
}

 

结果:

说明:

  • ngAfterContentInit会在外来内容被投影到组件中之后 调用,也就是说当test2组件以html的形式投影到test1组件之后执行,
  • 因为使用两种方式进行投影了两次,所以ngAfterContentInit执行了两次
  • 其他操作只会增加ngDoCheck的次数,并没有增加ngAfterContentInit的次数

 

  ngAfterContentCheck()

 test2.component.ts

import { Component, OnInit,Input ,OnChanges,DoCheck,SimpleChanges,AfterContentInit,AfterContentCheck} from '@angular/core';
@Component({selector: 'app-test2',templateUrl: './test2.component.html',styleUrls: ['./test2.component.css']
})
export class Test2Component implements OnInit,OnChanges,DoCheck,AfterContentInit,AfterContentCheck{@Input() test2_value1: string;@Input() test2_value2: string;constructor() { }ngOnInit() {//console.log("这里执行ngOnInit");
    }ngOnChanges(changes:SimpleChanges){//console.log(changes);for (let propName in changes) {let chng = changes[propName];let cur  = JSON.stringify(chng.currentValue);let prev = JSON.stringify(chng.previousValue);//console.log(`${propName}: 新值 = ${cur}, 旧值 = ${prev}`);
        }}ngDoCheck(){console.log("执行ngDoCheck");}ngAfterContentInit(){console.log("执行ngAfterContentInit");}ngAfterContentChecked(){console.log("执行ngAfterContentChecked");}
}

结果:

说明:

  • 在执行ngDoCheck之后 一定会执行一次ngAfterContentInit
  • 每次完成被投影组件内容的变更检测之后调用
  • 其他代码没贴出来,就是跟上一个是一样的

  ngAfterViewInit()

 test1.component.ts

import { Component, OnInit,OnChanges,ViewChild} from '@angular/core';
import {Test2Component} from "../test2/test2.component"@Component({selector: 'app-test1',//templateUrl: './test1.component.html',template: `<div>  <input  type="text" [(ngModel)]="test1_value1" >
<input  type="text" [(ngModel)]="test1_value2" ><ng-content></ng-content>
<app-test2 [test2_value1]="test1_value1" [test2_value2]="test1_value2"></app-test2> </div>`,styleUrls: ['./test1.component.css']
})
export class Test1Component implements OnInit, OnChanges{test1_value1:string;test1_value2:string;constructor() { } @ViewChild(Test2Component);ngOnInit() {this.test1_value1="1"this.test1_value2="2"}ngOnChanges(){console.log("onchange");}
}

test2.component.ts

import { Component, OnInit,Input ,OnChanges,DoCheck,SimpleChanges,AfterContentInit,AfterContentCheck, AfterViewChecked, AfterViewInit} from '@angular/core';
@Component({selector: 'app-test2',templateUrl: './test2.component.html',styleUrls: ['./test2.component.css']
})
export class Test2Component implements OnInit,OnChanges,DoCheck,AfterContentInit,AfterContentCheck ,AfterViewChecked, AfterViewInit{@Input() test2_value1: string;@Input() test2_value2: string;constructor() { }ngOnInit() {//console.log("这里执行ngOnInit");
    }ngOnChanges(changes:SimpleChanges){//console.log(changes);for (let propName in changes) {let chng = changes[propName];let cur  = JSON.stringify(chng.currentValue);let prev = JSON.stringify(chng.previousValue);//console.log(`${propName}: 新值 = ${cur}, 旧值 = ${prev}`);
        }}ngDoCheck(){console.log("执行ngDoCheck");}ngAfterContentInit(){console.log("执行ngAfterContentInit");}ngAfterContentChecked(){console.log("执行ngAfterContentChecked");}ngAfterViewInit(){console.log("执行ngAfterViewInit");}
}

结果:

说明:

  • 在每次创建了组件的子视图后调用,每次在test1组件中创建test2组件时都会调用,
  • 在test1组件中,需要使用@ChildView 装饰器,将test2component装饰一下

  ngAfterViewChecked

 test2.component.ts

import { Component, OnInit,Input ,OnChanges,DoCheck,SimpleChanges,AfterContentInit,AfterContentCheck, AfterViewChecked, AfterViewInit} from '@angular/core';
@Component({selector: 'app-test2',templateUrl: './test2.component.html',styleUrls: ['./test2.component.css']
})
export class Test2Component implements OnInit,OnChanges,DoCheck,AfterContentInit,AfterContentCheck ,AfterViewChecked, AfterViewInit{@Input() test2_value1: string;@Input() test2_value2: string;constructor() { }ngOnInit() {//console.log("这里执行ngOnInit");
    }ngOnChanges(changes:SimpleChanges){//console.log(changes);for (let propName in changes) {let chng = changes[propName];let cur  = JSON.stringify(chng.currentValue);let prev = JSON.stringify(chng.previousValue);//console.log(`${propName}: 新值 = ${cur}, 旧值 = ${prev}`);
        }}ngDoCheck(){console.log("执行ngDoCheck");}ngAfterContentInit(){console.log("执行ngAfterContentInit");}ngAfterContentChecked(){console.log("执行ngAfterContentChecked");}ngAfterViewInit(){console.log("执行ngAfterViewInit");}ngAfterViewChecked(){console.log("执行ngAfterViewChecked");}
}

结果:

说明:

  • 上图红色框是,页面刷新完后执行的ngAfterViewChecked,前两次是伴随init一起的,后面两个是,test1给test2赋值导致的
  • 上图绿色框是,更改test1中的一个值,导致了更改了test2的值执行的ngAfterViewChecked
  • 我再test1组件的两个input上,鼠标焦点来回切换时,同样也会执行ngAfterViewChecked,还是慎用这个钩子函数吧

  OnDestroy

test1.component.ts

import { Component, OnInit,OnChanges,ViewChild} from '@angular/core';
import {Test2Component} from "../test2/test2.component"@Component({selector: 'app-test1',//templateUrl: './test1.component.html',
  template: `<div>  <input  type="text" [(ngModel)]="test1_value1" ><input  type="text" [(ngModel)]="test1_value2" ><ng-content></ng-content><app-test2 [test2_value1]="test1_value1" [test2_value2]="test1_value2"></app-test2> <div *ngFor="let test of tests" appTest4 class="tests">{{test}}</div><input type="button"value="add" (click)="addDiv()"><input type="button"value="delete"(click)="deleteDiv()"></div>`,styleUrls: ['./test1.component.css']
})
export class Test1Component implements OnInit, OnChanges{test1_value1:string;test1_value2:string;tests:any;constructor() { }@ViewChild(Test2Component) viewChild:Test2Component;ngOnInit() {this.test1_value1="1"this.test1_value2="2"this.tests=[1,2,3]}ngOnChanges(){console.log("onchange");}addDiv(){this.tests.push("1212");}deleteDiv(){this.tests=[];}
}

test4.directive.ts

import { Directive, OnInit, OnDestroy  } from '@angular/core';@Directive({selector: '[appTest4]'
})
export class Test4Directive implements OnInit, OnDestroy{constructor() { }ngOnInit()    { console.log("test4 directive ngOnInit")}ngOnDestroy() { console.log("test4 directive ngDestroy");}
}

结果:

说明:

  • 建立一个directive来 监测test1 组件中的 div的生成与销毁
  • 开始有默认的三个值,所有ngOnInit执行了三次
  • 添加一个值,又执行一次ngOnInit
  • 删除所有的值,执行了4次ngDestroy

总结:

  由于生命周期的存在,angular提供了众多的生命周期的钩子,让我们能够很好的在发生变化的时候进行处理。

转载于:https://www.cnblogs.com/primadonna/p/9803083.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/352493.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BITMAPINFO结构

BITMAPINFO结构定义了Windows设备无关位图&#xff08;DIB&#xff09;的度量和颜色信息。 一、BITMAPINFO结构形式&#xff1a; typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO; 二、BITMAPINFO成员 bmi…

多媒体技术基础第四版林福宗pdf_意大利留学|没有绘画基础,还能考研艺术类专业吗?...

想学艺术专业&#xff0c;却没有绘画基础还能学艺术类专业么&#xff1f;意大利研究生的入学会简单一点 是典型的“宽进严出”想学艺术相关的专业&#xff0c;有2种看你是偏理论&#xff0c;还是偏实践。一起看一下&#xff01;偏实践方面纯艺类&#xff1a;油画、版画、雕塑、…

Spring Boot 1:Introduction

Spring Spring 在不断发展的过程中&#xff0c;边界不断扩张&#xff0c;需要的配置文件也越来越多&#xff0c;使用起来也越复杂&#xff0c;项目中也经常因为配置文件配置错误产生很多问题。即&#xff1a;Spring 逐渐变成了一个大而全的框架&#xff0c;背离它简洁开发的理念…

Pinely Round 3 (Div. 1 + Div. 2)

Pinely Round 3 (Div. 1 Div. 2) Pinely Round 3 (Div. 1 Div. 2) A. Distinct Buttons 题意&#xff1a;当前处于(0, 0)原点&#xff0c;给出若干个平面坐标轴上的点&#xff0c;是否可以仅选择三个方向便可以到达所有给出的点。 思路&#xff1a;到达单一坐标点最多需要…

在MFC,Win32程序中向控制台(Console)窗口输出调试信息

在MFC程序中输出调试信息的方法有两种&#xff0c;一种是使用TRACE宏&#xff0c;可以向Output窗口输出调试信息&#xff1b;另一种是用MessageBox&#xff0c;弹出消息框来输出调试信息&#xff0c;但会影响程序的运行。其实有一种方法可以更为方便的输出调试信息&#xff0c;…

C++程序内存泄漏都与哪些方面有关,该如何处理和避免

动态内存分配有几种: 一个是用了malloc/free, new/delete 第二个使用了第三方的库&#xff0c;库里面的API使用了第一种方法&#xff0c;他们需要你来释放空间&#xff0c;这个会在库的说明文档里有说明。 第三是程序递归&#xff0c;大量的程序递归和互相调用而不推出导致栈空…

unity vr是加一个摄像机就行吗_梦工厂和皮克斯员工创办的Baobab谈互动叙事:传统动画与VR动画的探索...

ACGN洞察访问三文娱网站3wyu.com查看产业必读文章Baobab工程师谈VR动画&#xff0c;以获得艾美奖和安妮奖的作品为例&#xff0c;介绍在跨媒体平台提升动画的质量、交互性和故事性。上个周末&#xff0c;Unite Shanghai 2019 在上海国际会议中心举行&#xff0c;来自世界各地的…

hbase regions_使用Regions ADF 11g进行Master Detail CRUD操作

hbase regions此示例演示了如何使用Regions在表之间创建Master Detail关系。 区域的主要目的是可重用性的概念。 使用区域和有限的任务流&#xff0c;我们可以将页面重用到许多其他页面中&#xff0c;以保持相同的功能并采用更简洁的方法 下载示例应用程序。 对于此示例&#…

(兔子繁殖问题)有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到三个月后每个月又生一对兔子,假如兔子都不死,问32个月过后的兔子总数为多少?...

网上关于这个问题有很多人说这个符合斐波那契数列&#xff0c;但是我个人在推算的时候发现并不是这样的&#xff0c;所以想自己解决这个问题 建立一个兔子类 属性有ID&#xff0c;age public class rabbit{ public  $id; public age; } 第1个月&#xff1a;(id1,age1)-------…

IF-ERRORLEVEL使用方法

我们都知道if是命令行下的一个条件判断语句&#xff0c;ERRORLEVEL是它的一个参数&#xff0c;翻译过来就是“错误返回码”的意思&#xff0c;它的作用是判断前一条命令的错误返回值&#xff0c;然后和定义的字符值进行比较&#xff0c;再决定进行什么动作今天远程一个客户&…

Eclipse IDE中的Java 9 module-info文件

请注意&#xff0c;本文并非旨在更新状态&#xff1b; 这只是基于我对Beta代码所做的一些实验而得出的快速更新。 已经有一段时间了&#xff0c;但是我要回到Eclipse IDE中尝试Java 9支持。 为了进行测试&#xff0c;我从Eclipse Project下载了最新的Oxygen &#xff08;4.7&…

局域网mysql数据库访问

1、调出mysql 命令界面 输入命令&#xff1a; mysql> use mysql Database changed mysql> select host,user,password from user; ------------------------------------------------------------ | host | user | password | --…

java.util中,util是什么意思

Util是utiliy的缩写&#xff0c;是一个多功能、基于工具的包。 java.util是包含集合框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类&#xff08;字符串标记生成器、随机数生成器和位数组、日期Date类、堆栈Stack类、向量Vector类等&#xff09…

Mathematics 9.0 绘制不等式确定的区域

在最新的mathematics软件中使用如下代码&#xff0c;无法产生程序&#xff1a; 在搜索了Mathematics 9.0 -> 帮助 -> 参考资料中心的内容&#xff0c;查到一个更简单好用的函数&#xff0c;正确结果如下&#xff1a;

无法打开包括文件:“mysql..h”: No such file or directory

出现这个问题后&#xff0c;根据网上提供的方法做了很多&#xff0c;但都没有用。后来在盘里面找了一下确实没有mysql.h这个文件&#xff0c;原来mysql必须选择complete安装方式才会有这个头文件。首先重新安装了一次mysql&#xff0c;然后选择自己的工程&#xff0c;进行环境配…

C# WPF 显示图片和视频显示 EmuguCv、AForge.Net测试

C# WPF 显示图片和视频显示 EmuguCv、AForge.Net测试 原文:C# WPF 显示图片和视频显示 EmuguCv、AForge.Net测试WPF 没有用到 PictureBox, 而是用Image代替. 下面我试着加载显示一个图片 。 XAML <Image x:Name"srcImg"Width"400"Height"300"…

一般一个前端项目完成需要多久_一种按周迭代的敏捷式项目管理方法

项目管理有很多理论&#xff0c;并且相关内容非常丰富&#xff0c;例如经典的项目管理的教材《项目管理&#xff1a;计划、进度和控制的系统方法》&#xff0c;字数达到了100万字。但是从源头来说&#xff0c;经典项目管理理论都是源自于对生产项目的过程中需要的管理的总结。对…

excel连接mysql 数据库

最近做个项目需要对收集到的数据进行实时刷新&#xff0c;原先考虑让获得的数据之间输出到txt文本&#xff0c;然后又文本导入到数据库&#xff0c;但是txt在修改查找的时候要把数据都读入到内存在进行相关改动&#xff0c;这样就很耗内存&#xff0c;而且文件占用率比较高&…

python jieba库下载_Python中jieba库安装步骤及失败原因解析

Python 中 jieba 库安装步骤及失败原因解析 作为计算机小白&#xff0c; Python 的流行也让我蠢蠢欲动&#xff0c; 在请教计算机 专业同学后&#xff0c;开始上网课自学 Python 基础知识。今天老师简单的一 句话“在命令行去运行 pip install jieba 的指令”安装 jieba 库&…

开放源代码库指南

微软.NET开发团队在博客上&#xff08;https://blogs.msdn.microsoft.com/dotnet/2018/10/15/guidance-for-library-authors/&#xff09;刚刚发布了.NET Library Guidance的第一个版本。这是一系列全新的文章&#xff0c;指导你为.NET创建高质量代码库。该指南包含我们已确定的…