1 生命周期钩子概述
组件共有9个生命周期钩子
1.1 生命周期的执行顺序
技巧01:测试时父组件传递对子组件的输入属性进行初始化操作
import { Component, Input, SimpleChanges, OnInit, OnChanges, DoCheck, AfterContentChecked, AfterViewInit, AfterContentInit, AfterViewChecked, OnDestroy } from ‘@angular/core‘; let logIndex : number = 1; @Component({ selector: ‘life‘, templateUrl: ‘./life.component.html‘, styleUrls: [‘./life.component.scss‘] }) export class LifeComponent implements OnInit, OnChanges, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy { @Input() name : string; logIt(msg : String) { console.log(`#${logIndex++} - ${msg}`); } constructor() { this.logIt("name属性在constructor里面的值为: " + this.name); } ngOnInit() { this.logIt("ngOnInit"); } ngOnChanges(changes : SimpleChanges){ this.logIt("name属性在ngOnChanges里面的值为: " + this.name); } ngDoCheck() { this.logIt("ngDoCheck"); } ngAfterContentInit() { this.logIt("ngAfterContentInit"); } ngAfterContentChecked() { this.logIt("ngAfterContentChecked"); } ngAfterViewInit() { this.logIt("ngAfterViewInit"); } ngAfterViewChecked() { this.logIt("ngAfterViewChecked"); } ngOnDestroy() { this.logIt("ngOnDestroy"); } }
TS
2 ngOnChanges
2.1 可变对象和不可变对象
在JavaScript中string类型是不可变对象,自定义的对象是可变对象;例如:
var a = "hello"; -> 变量a中存储的是字符串“hello”对应的内存地址
a = "warrior"; -> 变量a中存储的是字符串“warrior”对应的内存地址
结论:将不同的字符串赋值给同一个变量时,变量的值会发生改变;所以string类型是不可变类型【PS: 跟Java一样】
var user : {name : string} = {name : "warrior"}; -> 变量user中存储的是对象{name : "warrior"}对应的内存地址
user.name = "fury"; -> 变量user中还是存储的对象{name : "fury”}对应的内存地址,而且{name : "warrior"}和{name : "fury”}是同一个对象,所以他们的内存地址相同,故变量user中存储的值没有发生改变,改变的仅仅是变量user所指向的那个对象中的内容而已
结论:修改一个对象的内容并不会改变这个对象的内存地址,所以对象是可变对象
2.2 ngOnChanges
当输入属性的值发生改变时就会触发ngOnChanges
技巧01:如果输入属性的类型是一个对象时,需要区分是可变对象还是不可变对象,只有不可变对象时才会触发ngOnChanges;总之记住只要输入属性的值发生改变才会触发ngOnChanges
技巧02:ngOnChanges方法需要传入一个 SimpleChanges 类型的参数,可以利用该参数来查看输入属性改变前后的值,以及是否是初次赋值
技巧03:JSON.stringfy() 方法在将数据转化成JSON时可以进行格式化,例如
ngOnChanges(simpleChanges : SimpleChanges) { console.log(JSON.stringify(simpleChanges, null, 2)); }
2.2.1 子组件代码
<div class="panel panel-primary"> <div class="panel-heading">子组件</div> <div class="panel-body"> <p>问候语:{{greeting}}</p> <p>姓名:{{user.name}}</p> <p>年龄:{{age}}</p> <p> 消息:<input type="text" name="message" [(ngModel)]="message" /> </p> </div> <div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div> </div>
HTML
import { Component, OnInit, EventEmitter, Output, Input, OnChanges, SimpleChanges } from ‘@angular/core‘; @Component({ selector: ‘child‘, templateUrl: ‘./child.component.html‘, styleUrls: [‘./child.component.scss‘] }) export class ChildComponent implements OnInit, OnChanges { @Input() greeting : string; @Input() user : {name : string}; @Input() age : number; message : string; currentDate : Date; constructor() { } ngOnInit() { this.currentDate = new Date(); setInterval(() => { this.currentDate = new Date(); }, 1000); } ngOnChanges(simpleChanges : SimpleChanges) { console.log(JSON.stringify(simpleChanges, null, 2)); } }
TS
2.2.2 父组件代码
<div class="panel panel-primary"> <div class="panel-heading">父组件</div> <div class="panel-body"> <p> 问候语:<input type="text" name="greeting" [(ngModel)]="greeting" /> </p> <p> 姓名:<input type="text" name="name" [(ngModel)]="user.name" /> </p> <p> 年龄:<input type="number" [(ngModel)]="age" /> </p> <child [greeting]="greeting" [user]="user" [age]="age"></child> </div> <div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div> </div>
HTML
import { Component, OnInit } from ‘@angular/core‘; @Component({ selector: ‘parent‘, templateUrl: ‘./parent.component.html‘, styleUrls: [‘./parent.component.scss‘] }) export class ParentComponent implements OnInit { greeting : string = "Hello"; user : {name : string} = {name : "王杨帅"}; age : number = 8; currentDate : Date; constructor() { } ngOnInit() { this.currentDate = new Date(); setInterval(() => { this.currentDate = new Date(); }, 1000); } }
TS
2.2.3 效果图
3 ngDoCheck
3.1 变更检测机制
angular中由zone.js去负责监听浏览器中所有异步事件(事件[单击、双击]、定时器、ajax)来保证模板和组件属性的变化时同步的;
只要zone.js检测到有异步事件发生时所有监测机制是默认检测机制的组件都会触发ngDoCheck
应用:当输入属性的类型是可变对象时,即使可变对象的内容发生了变化 ngOnchanges 也不会被调用,但是 ngDoCheck 会被调用;所以我们可以利用 ngDoCheck 来检测可变对象的变化
坑01:zone.js检测到任何一个组件有异步事件发生都会让所有采用默认变更检测机制的组件执行 ngDoCheck,所以 ngDoCheck 方法要慎用,而且逻辑不能太复杂,不然会影响性能
3.2 变更检测策略
3.2.1 default
angular默认的变更检测策略
如果所有的组件都是默认的变更检测策略,那么当一个组件发生改变时angular会对所有的组件进行变更检查
3.2.2 onPush
待更新...
3.3 代码汇总
3.3.1 父组件代码
<div class="panel panel-primary"> <div class="panel-heading">父组件</div> <div class="panel-body"> <p> 问候语:<input type="text" name="greeting" [(ngModel)]="greeting" /> </p> <p> 姓名:<input type="text" name="name" [(ngModel)]="user.name" /> </p> <p> 年龄:<input type="number" [(ngModel)]="age" /> </p> <child [greeting]="greeting" [user]="user" [age]="age"></child> </div> <div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div> </div>
HTML
import { Component, OnInit } from ‘@angular/core‘; @Component({ selector: ‘parent‘, templateUrl: ‘./parent.component.html‘, styleUrls: [‘./parent.component.scss‘] }) export class ParentComponent implements OnInit { greeting : string = "Hello"; user : {name : string} = {name : "王杨帅"}; age : number = 8; currentDate : Date; constructor() { } ngOnInit() { this.currentDate = new Date(); // setInterval(() => { // this.currentDate = new Date(); // }, 1000); } }
TS
3.3.2 子组件代码
<div class="panel panel-primary"> <div class="panel-heading">子组件</div> <div class="panel-body"> <p>问候语:{{greeting}}</p> <p>姓名:{{user.name}}</p> <p>年龄:{{age}}</p> <p> 消息:<input type="text" name="message" [(ngModel)]="message" /> </p> </div> <div class="panel-footer">{{currentDate | date : "yyyy-MM-dd HH:mm:ss"}}</div> </div>
HTML
import { Component, OnInit, EventEmitter, Output, Input, OnChanges, SimpleChanges } from ‘@angular/core‘; import { DoCheck } from ‘@angular/core/src/metadata/lifecycle_hooks‘; @Component({ selector: ‘child‘, templateUrl: ‘./child.component.html‘, styleUrls: [‘./child.component.scss‘] }) export class ChildComponent implements OnInit, OnChanges, DoCheck { @Input() greeting : string; @Input() user : {name : string}; oldName : string; // 存储上一次的值 changeNum : number = 0; // 非本组件触发ngDoCheck方法的次数 changeDetected : boolean; // 是否是本组件触发ngDoCheck方法 @Input() age : number; message : string; currentDate : Date; constructor() { } ngOnInit() { this.currentDate = new Date(); // setInterval(() => { // this.currentDate = new Date(); // }, 1000); } ngOnChanges(simpleChanges : SimpleChanges) { console.log(JSON.stringify(simpleChanges, null, 2)); } ngDoCheck() : void { // 如果检测到是本组件的输入属性变化 if (this.user.name !== this.oldName) { this.changeDetected = true; console.log("ngDoCheck: user.name 从 "+ this.oldName +" 变成了 "+ this.user.name +" "); this.oldName = this.user.name; } if (this.changeDetected) { this.changeNum = 0; // 本组件触发的ngDoCheck就进行清零操作 } else { // 非本组件触发的ngDoCheck方法就进行加一操作 this.changeNum = this.changeNum + 1; console.log("ngDoCheck: user.name没有变化,ngDoCheck方法被调用了" + this.changeNum + "次"); } this.changeDetected = false; } }
TS
3.3.3 效果展示
原文地址:https://www.cnblogs.com/NeverCtrl-C/p/9249017.html