ngModel源码浅解
前言
- 之前看过vue的双向绑定原理,并实现过简易的demo,但是很少见过有讲解angular下,双向绑定是如何实现的,所以看了下NgModel源码,发现大同小异,特来说下
- 目前来说只说下ngModel是如何实现的,不涉及属性绑定及指令方面的知识
- 本篇文章需要知道如下知识才可以阅读
自定义表单控件
响应式表单之FormControl
一个ngModel,使用了几个指令?
- 一般当这么说,那么肯定意味着使用了不只一个指令,否则也不会浪费时间说一个确定的事实
组件也是继承于指令的,所以这么说应该也不算错
NgModel
和ControlValueAccessor实现类
,当你要使用NgModel
时,实际上是使用了两个指令NgModel
负责注册一些函数,所有ControlValueAccessor实现类
实现的4个方法(一个可选禁用方法),最终都是通过NgModel
的来使用的ControlValueAccessor实现类
是规定绑定的内部逻辑,比如什么时候发送值被变更,当出现值写入时如何处理
流程示意图
注册
- 所谓注册就是当值变更时.实现类应该用哪些方法去通知已经变更
- 实现类中的
registerOnChange(fn)
,fn就是在注册阶段传入的,当在这个阶段调用实现类.registerOnChange(fn)
,函数被赋值到实现类中,而当值变更时实现类则调用此函数通知值已变更 - 此阶段,总共有6个方法被注册(验证器分为同步,异步)
- 实现类中registerOnChange,当视图中值发生了变更调用传入函数
- 实现类中registerOnTouched,默认中的实现类是当失去焦点调用传入函数
- NgModel中FormControl实例中registerOnChange,当值变化是调用传入函数
- NgModel中FormControl实例中registerOnDisabledChange,禁用状态变化时,调用实现类中的
setDisabledState
方法- 验证器的
registerOnValidatorChange
当验证器的输入属性变化时调用传入函数
- 传入函数已经写在
shared.ts
文件中
输入
- 当[ngModel]传入的值变更后会被
NgModel
的ngOnchanges
钩子捕获到 - 如果值变更或为初始值,那么会调用钩子中的
this._updateValue(this.model)
- 此方法会触发类中
FormControl实例
的值变更 - 当值变更时,上述注册方法中的3会执行
传入函数
,函数中会触发实现类中的writeValue
方法,此时实现类收到了变更值 - 在默认的方法中,收到变更值后,是利用angular的渲染器,写入到
input
元素的value中 - 输入流程结束
输出
- 当
input
或compositionend
事件时,会调用传入函数onChange
.当blur
事件时,会调用传入函数onTouched
- 函数收到值后判断是不是处在更新时机,如果是那么更新调用
NgModel
中的viewToModelUpdate
- 此方法更新值并发射信号
ngModelChange
告知值已经变更
难点
- 大家应该都知道自定义表单控件怎么写,明明没有写过
NgModel
input属性和ngModelChange
output事件,但是却在实现了ControlValueAccessor
类后神奇的实现了. - 这里其实就是因为
NgModel
指令的选择器是[ngModel]:not([formControlName]):not([formControl])
,也就是说,只要不是响应式表单,那么所有带ngModel的都会自动使用这个指令 - 并且该指令在构造时会找他的
ControlValueAccessor实现类
,当找到后,通过将一些变更需要出发的函数告知实现类
而建立了关联
源码注释
- 在看源码时也对立面的函数,方法已经相关语句做了注释,如果大家看上面的还是感觉不太清晰,可以参照注释源码,希望能给予你们帮助
- ng_model.ts
- shared.ts
- default_value_accessor.ts
疑问
- 如果有哪里描述的有问题或者不对的请多提宝贵意见
相关推荐
chensen 2020-11-14
lwnylslwnyls 2020-11-06
ATenhong 2020-10-15
yanzhelee 2020-10-13
佛系程序员J 2020-10-10
guojin0 2020-10-08
佛系程序员J 2020-10-08
bluewelkin 2020-09-16
wwzaqw 2020-09-04
zhongdaowendao 2020-09-02
favouriter 2020-08-18
奎因amp华洛 2020-08-15
一青年 2020-08-13
千锋 2020-08-10
nangongyanya 2020-08-09
dongxurr 2020-08-08
明天你好 2020-08-03
kyelu 2020-08-03
Ashes 2020-08-03