前言
- 之前看过vue的双向绑定原理,并实现过简易的demo,但是很少见过有讲解angular下,双向绑定是如何实现的,所以看了下NgModel源码,发现大同小异,特来说下
- 目前来说只说下ngModel是如何实现的,不涉及属性绑定及指令方面的知识
- 本篇文章需要知道如下知识才可以阅读
一个ngModel,使用了几个指令?
- 一般当这么说,那么肯定意味着使用了不只一个指令,否则也不会浪费时间说一个确定的事实
NgModel
和ControlValueAccessor实现类
,当你要使用NgModel
时,实际上是使用了两个指令NgModel
负责注册一些函数,所有ControlValueAccessor实现类
实现的4个方法(一个可选禁用方法),最终都是通过NgModel
的来使用的ControlValueAccessor实现类
是规定绑定的内部逻辑,比如什么时候发送值被变更,当出现值写入时如何处理
流程示意图
注册
- 所谓注册就是当值变更时.实现类应该用哪些方法去通知已经变更
- 实现类中的
registerOnChange(fn)
,fn就是在注册阶段传入的,当在这个阶段调用实现类.registerOnChange(fn)
,函数被赋值到实现类中,而当值变更时实现类则调用此函数通知值已变更 - 此阶段,总共有6个方法被注册(验证器分为同步,异步)
输入
- 当[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实现类
,当找到后,通过将一些变更需要出发的函数告知实现类
而建立了关联
源码注释
疑问
03-05 14:06