几种实现双向绑定的做法
数据=>视图
视图=>数据
目前几种主流的mvc(vm)框架都实现了单向数据绑定,而我所理解的双向数据绑定无非就是在单向绑定的基础上给可输入元素(input、textare等)添加了change(input)事件,来动态修改model和view,并没有多高深。所以无需太过介怀是实现的单向或双向绑定。
实现数据绑定的做法有大致如下几种:
- 发布者-订阅者模式(backbone.js)
- 脏值检查(angular.js)
- 数据劫持(vue.js)
发布者-订阅者模式: 一般通过sub,pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是vm.set('property',value)
这种方式现在毕竟太low了,我们更希望通过vm.property = value
这种方式更新数据,同是自动更新视图,于是有了下面两种方式
脏值检查: angular.js是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过setInterval()
定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测,大致如下:
- DOM事件,譬如用户输入文本,点击按钮等。
(ng-click)
- XHR响应事件
($http)
- 浏览器Location变更事件
($location)
- Timer事件
($timeout,$interval)
- 执行
$digest()或$apply()
数据劫持: vue.js则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter、getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
第一步:需要observer的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化。
第二步:compile解析模板字指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加函数监听数据的订阅者,一旦数据变动,收到通知,更新视图
第三步:watcher订阅者是observer和compile之间通信的桥梁,主要做的事情是:
1. 在自身实例化时属性订阅器(dep)里面添加自己
2. 自身必须有一个updater()方法
3. 待属性变动dep.notice()通知时,能调用自身的updater()方法,并触发Compile中绑定的回调,则攻成身退
第四步:MVVM 作为绑定的入口,整和 Observer,Compile 和 Watcher 三者,通过 Observer 来监听 model 数据变化表,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer,Compile 之间的通信桥梁,达到数据变化=>视图更新;视图交互变化=>数据 model 变更的双向绑定效果。
MVVM作为绑定的入口,整和Observer,Compile和Watcher三者,通过Observer来监听model数据变化表,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer,Compile之间的通信桥梁,达到数据变化=>视图更新;视图交互变化=>数据model变更的双向绑定效果。
MVVM响应式原理代码实现