碎碎念:知识点梳理归纳,如果有什么不对的感谢大家指正一起学习!
在ngDoCheck钩子之前需要了解一下
数据改变了----> NGZone获取了 ----> 通知angular ----> 执行变化检测
例:在子组件添加ngDoCheck方法
// html
我是子组件
问候语:{{greetings}}
姓名:{{user.name}}
// ts
export class TestComponent implements OnInit, DoCheck {
@Input() greetings: string;
@Input() user: { name: string };
noChangeCount: number = 0;
oldUserName: string;
changeDetected: boolean = false;
constructor() {}
ngDoCheck(): void {
if (this.user.name !== this.oldUserName) {
this.changeDetected = true;
console.log("DoCheck:user.name从" + this.oldUserName + "变为" + this.user.name);
this.oldUserName = this.user.name;
}
if (this.changeDetected) {
this.noChangeCount = 0;
} else {
this.noChangeCount = this.noChangeCount + 1;
console.log("DoCheck:user.name值没发生变化时,doCheck方法已经被调用" + this.noChangeCount + "次");
}
this.changeDetected = false;
}
}
逻辑:
效果:
总结:
是Angular默认的变化检测策略,也就是脏检查,只要有值发生变化,就全部从父组件到所有子组件进行检查。
触发条件:
优点:
每一次有异步事件发生,Angular都会触发变更检测(脏检查),从根组件开始遍历其子组件,对每一个组件都进行变更检测,对dom进行更新
缺点:
有很多组件状态(state)没有发生变化,无需进行变更检测,进行没有必要的变更检测,如果你的应用程序中组件越多,性能问题会越来越明显
就是只有当输入数据(即@Input)的引用发生变化或者有事件触发时,组件才进行变化检测。这种策略检查不彻底,但效率高。
相比Default只需要在@Component装饰器中加上一句:
changeDetection:ChangeDetectionStrategy.OnPush
触发条件:
Input()
优点:
组件的变更检测(脏检查)完全依赖于组件的输入(@Input),只要输入值不变,就不会触发变更检测,也不会对其子组件进行变更检测,在组件很多的时候会有明显的性能提升
缺点:
必须保证输入(@Input)是不可变的,手动进行变化检测
手动变化检测
通过引用变化检测对象ChangeDetectorRef
ChangeDetectorRef介绍
实现逻辑:
代码:
父组件
// html
变更检测策略
// ts
@Component({
selector: 'app-prouct-one',
templateUrl: './prouct-one.component.html',
styleUrls: ['./prouct-one.component.scss']
})
export class ProuctOneComponent implements {
title: string = 'default 策略';
star: Star = new Star('周', '杰伦');
changeStar() {
this.star.firstName = '吴';
this.star.lastName = '彦祖';
}
changeStarObject() {
this.star = new Star('刘', '德华');
}
}
export class Star {
constructor(
public firstName: string,
public lastName: string
) { }
}
子组件
// html
{{ title }}
{{star.firstName}}{{star.lastName}}
// ts
@Component({
selector: 'app-movie',
templateUrl: './movie.component.html',
styleUrls: ['./movie.component.scss'],
})
export class MovieComponent implements {
@Input() title: string;
@Input() star;
constructor(
) { }
}
效果:
总结:
代码:
父组件的代码不变。下面是子组件的代码
// html
{{ title }}
{{star.firstName}}{{star.lastName}}
点击我
// ts
import { Component, OnInit, Input, DoCheck, ChangeDetectionStrategy, OnChanges, ChangeDetectorRef, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-movie',
templateUrl: './movie.component.html',
styleUrls: ['./movie.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MovieComponent implements OnInit, DoCheck, OnChanges {
@Input() title: string;
@Input() star;
constructor() { }
ngOnChanges(changes: SimpleChanges): void {
console.log("changes", JSON.stringify(changes, null, 2))
}
change() {
console.log("我点击了")
}
}
效果:
总结:
代码:
只需要稍微的修改一下子组件的ts代码
// ts
import { Component, OnInit, Input, DoCheck, ChangeDetectionStrategy, OnChanges, ChangeDetectorRef, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-movie',
templateUrl: './movie.component.html',
styleUrls: ['./movie.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MovieComponent implements OnInit, DoCheck, OnChanges {
@Input() title: string;
@Input() star;
constructor(
private cdr: ChangeDetectorRef
) { }
ngOnChanges(changes: SimpleChanges): void {
console.log("changes", JSON.stringify(changes, null, 2))
}
ngDoCheck(): void {
this.cdr.markForCheck();
}
change() {
console.log("我点击了")
}
}
效果:
总结:
相关链接: