AngularJS的数据双向绑定是怎么实现的?
👍: 关于 AngularJS 的数据绑定
单向绑定(ng-bind) 和 双向绑定(ng-model) 的区别:
ng-bind 单向数据绑定($scope -> view),用于数据显示,简写形式是 {{}}
。<span ng-bind="val"></span>
两者的区别在于页面没有加载完毕 {{val}}会直接显示到页面,直到 Angular 渲染该绑定数据(这种行为有可能将 {{val}}让用户看到);而 ng-bind则是在 Angular 渲染完毕后将数据显示。ng-model是双向数据绑定($scope -> view and view ->$scope),用于绑定值会变化的表单元素等。<input type="text" ng-model="val" />
之前的总结: 2.4.0 angular双向数据绑定
有三个概念:
- $digest():脏值检查循环
- $watch:添加监听
- $apply:提供上下文执行表达式
双向数据绑定(bi-directional)意味着如果视图改变了某个值,数据模型会通过脏检查观察到这个变化,而如果数据模型改变了某个值,视图也会依据变化重新渲染。
当你写下表达式如{{ aModel }}时,AngularJS在幕后会为你在scope模型上设置一个watcher,它用来在数据发生变化的时候更新view。这里的watcher和你会在AngularJS中设置的watcher是一样的:
对于所有绑定给同一$scope元素的UI对象,只会添加一个$watch到$watch列表中(一个数据一个$watcher,对象会有一个,里面的值还会有,数组中每个对象都有一个 )。这些$watch列表会在$digest循环中通过一个叫做“脏值检查”的程序解析
- 假设你在一个ng-click指令对应的handler函数中更改了scope中的一条数据,
- 此时AngularJS会自动地通过调用$digest()来触发一轮$digest循环。
- 当$digest循环开始后,它会触发每个watcher。
- 这些watchers会检查scope中的当前model值是否和上一次计算得到的model值不同。
- 如果不同,那么对应的回调函数会被执行。调用该函数的结果,就是view中的表达式内容(译注:诸如{{ aModel }})会被更新。
除了ng-click指令,还有一些其它的built-in指令以及服务来让你更改models(比如ng-model,$timeout等)和自动触发一次$digest循环。如下:
谈起angular的脏检查机制(dirty-checking), 常见的误解就是认为: ng是定时轮询去检查model是否变更。 其实,ng只有在指定事件触发后,才进入$digest cycle:
- DOM事件,譬如用户输入文本,点击按钮等。(ng-click)
- XHR响应事件 ($http)
- 浏览器Location变更事件 ($location)
- Timer事件($timeout, $interval)
- 执行$digest()或$apply()
上述事件发生->$digest()循环->触发每个watcher->watcher检查scope中的当前model值和上一次计算得到的model值是否不同->如果不同,那么$watch()对应的回调函数会被执行->调用该函数的结果,就是view中的表达式内容(译注:诸如{{ aModel }})会被更新
angularJS并不直接调用$digest(),而是调用$scope.$apply(),后者会调用$rootScope.$digest()。因此,一轮$digest循环在$rootScope开始,随后会访问到所有的children scope中的watchers。