早在AngularJS时代(即Angular1)即有双向绑定这个功能,当然这个概念不见得NG是最早的(ActionScript也有),但NG的流行助其推广开来,这是毋庸置疑的,今天的Vue也有双向绑定,React本身并没有提供支持,但也可以自己实现做到。那,双向绑定是如何做到的,利弊又是什么呢。
以NG为例,这里就深度了解下。
抛砖引玉。
[toc]
使用
先看下双向绑定的使用,如下组件中声明username,使用[(ngModel)]
进行双向绑定后,则M与V可以实时同步,这就是双向绑定。
1 | <p> |
这样的好处就是视图层与表单对象保持一致,你直接获得了表单对象的数据值,并且类型问题也都提前处理好了,不需要自己再操作。
实现
用起来方便,接下来看看NG是如何实现的吧。
[(ngModel)]
是语法糖
要知道[(ngModel)]
是语法糖,拆开可以看作是 <input [ngModel]="username" (ngModelChange)="username=$event"/>
, ngModel是个指令
,ngModelChange是指令中暴露出来的一个方法,所以聚焦ngModel指令的实现逻辑。
data => view 使用[]
view => data 使用()
[ngModel]
当我们在数据中修改了name的值,视图上的值就会
实时
变化
两个疑问
- NG如何知道对象变化?
脏检查
- NG如何更新值到最终的原生元素身上呢?
修改元素value属性
脏检查Dirty checking
脏检查全称是脏数据检查
,即产生了变化的数据。
NG中异步操作,比如Click,比如XHR,自动触发change detection,发现这些变化,然后执行更新动作。
但是这些变化,我理解也不是只要你变了就立即去做更新,而是model稳定后,批量更新
注意,NG不是定时轮询去检查
更新视图
通过指令找到nativeElement,修改value属性。
1 | // packages/forms/src/directives/ng_model.ts |
1 |
|
1 | // packages/platform-browser/src/dom/dom_renderer.ts |
(ngModelChange)
监测到表单输入值的变化,即更新到数据对象中
1 |
|
1 |
|
关键点如上,原理大致明白了,那抛开框架,如何手写个双向绑定呢。
其它手段
Object.defineProperty
- IE9支持
- Vue v2 双向绑定实现原理
1 | const obj = {}; |
Proxy
IE不支持
Proxy为ES6特性
Vue v3双向绑定实现原理
1
2
3
4
5
6
7
8
9
10
11
12
13const obj = {};
const handler = {
get: function (target, prop) {
console.log('获取value值', target[prop]);
return target[prop];
},
set: function (target, prop, value) {
console.log('设置value值', value);
target[prop] = value;
},
};
const proxy = new Proxy(obj, handler);