写在前面
Vue.js 最核心的功能有两个,一是响应式的数据绑定系统,二是组件系统。我所理解的双向数据绑定就是当数据变化时视图自动更新,当视图变化时数据自动更新。
实现数据绑定的做法有大致如下几种:
- 发布者-订阅者模式(backbone.js)
- 脏值检查(angular.js)
- 数据劫持(vue.js)
发布者-订阅者
一般通过sub, pub的方式实现数据和视图的绑定监听,更新数据方式通常做法是 vm.set(‘property’, value)。
脏值检查
angular.js 是通过脏值检测的方式比对数据是否有变更,来决定是否更新视图,最简单的方式就是通过 setInterval() 定时轮询检测数据变动,当然Google不会这么low,angular只有在指定的事件触发时进入脏值检测。
数据劫持
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
Vue双向绑定
当视图变化时数据自动更新时比较简单,可以通过监听视图的change事件,当视图变化直接调用更新函数更新数据。
当数据变化时视图自动更新是双向绑定的重点。
让我们先来看一下官网的这张数据绑定的说明图:
原理图告诉我们,Data中的属性定义了getter、setter对属性进行劫持,当属性值改变是就会notify通知watcher对象,而watcher对象则会notify到view上对应的组件进行更新,然后我们就看到了视图的更新了,反过来当在视图输入数据时,也会触发订阅者watcher,更新最新的数据到data里面,这样model数据就能实时响应view上的数据变化了,这样一个过程就是数据的双向绑定了。
原理分析
通过上面的介绍我们发现整个过程需要需要几个对象:
- 订阅器Dep:实现新增订阅者、通知订阅者的功能
- 监听器Observer:通过Object.defineProperty()定义属性的getter、setter。
- 订阅者Watcher:实现view视图指令及数据和model层数据联系的管道,当在执行编译时候,他会把对应的属性创建一个Watcher对象让他和数据层model建立起联系。但数据发生变化是会触发update方法更新到视图上view中,反过来亦然。
- 编译器Compile:负责解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。