变更检测是在js事件循环过程中,将组件的数据变化反映到视图上的一种机制
具体过程如下:
几点关键的:
1、子组件的ngonchange ngDoCheck ngAfterContentChecked 是在父组件更新dom(第9步)前完成
2、在所有子组件的afterViewChecked钩子执行之前,父组件的ViewChild查询表就会更新,在所有子组件的afterViewChecked钩子执行之后,父组件的AfterViewChecked钩子会执行
3、给组件设置了onpush策略,会影响的是组件是否执行变更检测,但是组件的ngonchange, ngdocheck,ngaftercontentchecked钩子照样执行,ngafterviewchecked钩子也会执行,即使跳过了变更检测
4、细化下第4条步骤,第4条的嵌套视图指的是:组件内的视图容器所包含的实例,
考虑组件设置了onpush的场景,若嵌套视图的来源组件是本组件,因为本组件未参与变更检测,那么该视图实例不参与变更检测;若嵌套视图的来源组件参与了本次变更,那么视图实例参与变更检测
若组件为默认策略,那么嵌套视图都参与变更检测,与来源组件无关
第4条的疑问由下面的场景衍生思考而来:
zorro的树组件接收templateRef作为输入,但是zorro的所有组件检测策略默认都是onpush模式,
现象是:在修改了节点的属性(online 及 total值)后,dom变更处的dom能刷新。但是并没有修改组件输入值的引用,也就意味着tree组件的变更检测没有执行,那为什么dom变更处的dom能刷新呢?
例子----理解变更检测在js时间循环中处于什么位置
区域分析组件订阅了树组件的事件,点击区域树组件的收缩按钮,区域分析组件调用ngx-datatable的recaculate,重新计算表格的尺寸,完成
树组件的收缩样式由区域分析组件的tabWidthStatus变量控制,tabWidthStatus变量在区域分析组件的changeWidth函数中修改
树组件
区域分析组件
changeWidth emit事件回调
订阅函数如下,在计算表格尺寸的时候,需要加上一个延时整个功能才能完美
仔细分析,这里存在一个时序的问题,对于这个过程分析如下:
若是不加延时的话,步骤5会在步骤二的位置执行,这样计算表格尺寸还是基于老的样式
这里添加另外一个情况,对于最左侧二级目录收缩,也需要对表格重新计算尺寸。二级目录加了200ms动画,而表格的尺寸要依赖动画过后的dom尺寸,所以为了适配上面这两种收缩的情况,最终要加300ms延时
例子----理解变更检测流程内部viewChild的获取时机
在组件中可以通过ViewChild装饰器获取组件模板中的templateRef, elementRef, ViewContainer。
这里以典型的获取TemplateRef作例子,ngx-datatable表格组件中需要操作栏,操作栏需要自定义,
在模板中使用ng-template标签定义模板(注意这个模板不要定义在第二个ngIf标签内部,具体原因往下看)
组件代码中通过@ViewChild装饰器获取,并且在ngAfterViewInit钩子函数之后才能拿到
在angular7版本之后,所有的ViewChild都在ngAfterViewInit钩子函数之后才能拿到(很好理解,只有当View准备好之后,才能获取VIewChild);
回到之前的问题,为什么把ng-template放在ngIf中,就获取不到呢?
仔细看看变更检测流程的第11步,当前组件的ViewChild更新会在子组件变更检测结束之后进行,ngIf指令作为子组件,会判断输入是否为true,因为页面默认展示第一个tab,所以第二个ngIf的输入初始为false,所以在ngIf结束检测之后,ng-tamplate就不存在,所以通过ViewCHild自然获取不到;
备注:angular老版本ViewChild是在ngonInit时就会获取的,所以不存在上面说的问题,这里特别强调的是angular7版本之后
标签:检测,流程,视图,ViewChild,钩子,组件,angular,变更 From: https://www.cnblogs.com/querybest/p/18512466