angularjs 的数据绑定实现原理
在angularjs1.X中存在了三种数据绑定的方式,用于数据的同步、展示。在angularjs1.3之前,angularjs只存在两种方式:two-way-binding和one-way-bindng,而后则引入了称为one-time-binding的绑定机制。
目前angularjs中存在以下三种数据绑定方式:
- two-way-binding
- one-way-binding
- one-time-binding
two-way-binding
angularjs中的Two-way-binding的作用是将Model和View关联起来,任何一侧的数据变更都会更新另一侧的数据。
常见场景是页面中的输入区域。双向绑定可以很容易的将输入控件的值关联到数据模型中。
通过ng-model我们可以很容易的将输入框(view)的值和name(Model)关联起来。在双向数据流的作用下,无论是我们修改输入框的值还是修改name,另外一侧都将及时更新到新数据。
ng-model是angularjs内置的一个指令用来实现双向绑定。ng-model在不同生命周期中,有不同的逻辑处理。
1、compilationphase:
- ng-model指令和input指令会被合并处理给input标签注册keydown事件(DOMEvent);
- interpolation则注册一个$watch用来订阅change事件(angularjsEvent)。
2、RuntimePhase
- 用户输入触发keydown
- input指令捕获keydown事件,调用$apply来请求更新动作。
- angularjs更新值到Model
- 进入$digest上下文
- $watch表达式检测到Model发生了change,通知interpolation,请求更新DOM。
- angularjs托管结束,退出托管,交还控制权到JavaScript执行上下文。
- 最后浏览器重新渲染文本。
One-way-binding
不同于Two-way-binding的双向流动,one-way-binding的数据流向是单向,即只会从model流向view,而不会从view流向model。因此,one-way-binding用来展示数据,而不是获取输入。
在angularjs中,one-way-binding则有两种语法:ng-bind和{{expression}}。
{{name}}
对于one-way-binding来说,内部机制和two-way-binding有部分相同的机制。
1、compilationphase:
- interpolation注册一个$watch用来订阅change事件(angularjsEvent)。
2、runtimephase:
- angularjs进入$digest。
- expression的$watch检测到数据发生变更,通知interpolation,请求更新DOM。
- angularjs托管结束,退出托管,交还控制权到JavaScript执行上下文。
- 最后浏览器重新渲染文本。
one-time-binding
1.3之后,angularjs实现了一个叫one-time-binding的机制。本质上它的机制和其他两种方式没太多差异,但在数据更新时候表现的不太一样。
one-time-binding同样会注册$watch来监听数据变化,但它会在第一次检测到数据非Undefined时候取消监听。
{{::name}}
对于上面的代码,假设name从undefined->angularjs->angular,最终渲染的结果是angularjs,而不是angular。这就是one-time-binding的特殊之处,当name从undefined变化为angularjs之后,被认定为name的状态已经是stable,因此将取消$watch,即不再监听数据变化。
那么,假设name从''->angularjs->angular,则渲染结果是'',即空字符串(第一次的值)。因为one-time-binding在计算stable时候使用的严格相等,即newVal===undefined,如果是,则继续保留$watch等待下一次的比较;否则,状态变更为stable,取消$watch,数据转化为最终态。
结束
在我看来,angularjs核心在于angularjscontext和$digest。
angularjscontext保证angularjs可以捕获到各种事件,用户输入、鼠标事件、键盘事件、甚至$settimeout和$http等异步行为的状态流转。
而$digest则保证angularjs可以确认是否要更新数据。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。