Angular中ngModel触发无关getter及生命周期相关疑问
Angular 组件行为测试示例
组件代码
blank-counter.component.ts
@Component({ selector: 'app-blank-counter', templateUrl: './blank-counter.component.html', styleUrls: ['./blank-counter.component.css'] }) export class BlankCounterComponent implements OnInit, OnChanges { constructor() { } currentDateTime = new Date(); ngOnInit() { console.log('blank counter ngOnInit()'); } ngOnChanges(changes: SimpleChanges) { // changes.prop contains the old and the new value... console.log('ngOnChanges, changes:'+changes); } //@Input() _counterValue = 0; // notice the '_' get counterValue() { console.log('get counterValue()'); return this._counterValue; } }
blank-counter.component.html
<p>blank-counter works!</p> {{counterValue}} <p>Input with ngModel:<input type="text" [ngModel]="abc"/></p> <p>Input without ngModel:<input type="text" value="abc"/></p> <p>Current Date Time:{{currentDateTime}}</p>
template-driven-form-ex2.component.html
<p>template-driven-form-ex2 works!</p> <app-blank-counter name="blankCounter"></app-blank-counter>
template-driven-form-ex2.component.ts
@Component({ selector: 'app-template-driven-form-ex2', templateUrl: './template-driven-form-ex2.component.html', styleUrls: ['./template-driven-form-ex2.component.css'] }) export class TemplateDrivenFormEx2Component implements OnInit { constructor() { } ngOnInit() { } }
问题解答
问题1:在无ngModel的输入框中输入文本时,counterValue的getter不会被调用;但在绑定[ngModel]="abc"(组件未定义abc属性)的输入框中输入文本时,该getter会被调用,请问是否因模板刷新导致?
是,核心原因是变更检测触发了模板刷新:
- 无
ngModel的原生输入框,输入操作仅修改DOM自身值,不会触发Angular变更检测,模板不会重新渲染,counterValue的getter自然不会执行。 - 绑定
[ngModel]的输入框,即便绑定的abc未定义,Angular仍会维护双向绑定的触发逻辑。用户输入时,Angular尝试更新绑定变量(即便变量不存在),这个操作会触发组件的变更检测,导致模板重新渲染,因此counterValue的getter会被调用。
问题2:在绑定[ngModel]的输入框中输入文本时,ngOnChanges钩子未被触发,原因是什么?
ngOnChanges仅在组件被@Input()标记的输入属性发生变化时触发。
当前BlankCounterComponent中没有任何带@Input()的属性,绑定[ngModel]的abc也不是该组件的输入属性,只是模板中未定义的变量。输入操作既没有修改组件的输入属性,也没有触发输入属性的更新流程,所以ngOnChanges不会被触发。
问题3:绑定[ngModel]的输入框输入文本时counterValue的getter被调用,但currentDateTime = new Date()未执行、显示值不变,原因是什么?
currentDateTime = new Date()是组件实例初始化阶段的属性赋值语句,只会在组件创建时执行一次,后续不会自动重复运行。
模板刷新时,Angular只会重新计算插值表达式的取值,也就是读取currentDateTime已有的Date对象值,不会重新执行初始化时的赋值代码。如果想让日期随模板刷新更新,需要将currentDateTime改为getter,或者在变更检测时手动更新其值。
内容的提问来源于stack exchange,提问作者user1169587
相关产品推荐
相关产品推荐

