浅谈vue,angular,react数据双向绑定原理分析
在前端开发中,数据双向绑定是指视图和模型之间的同步更新机制。当模型数据改变时,视图会自动更新;反之,当视图发生变化时,模型数据也会同步更新。本文将对Vue、Angular和React这三种前端框架的数据双向绑定原理进行剖析。
一、传统做法
在传统的前端开发中,前端维护状态,手动操作DOM更新视图。前端框架对服务器数据通过模版进行渲染。当用户产生了一个动作之后,我们通过document.getElementBy... 手动进行DOM更新。这种方式需要手动操作DOM,因为框架只管首次渲染,不追踪状态监听变化。
二、双向数据绑定
双向数据绑定是指视图和模型之间的同步更新机制。当模型数据改变时,视图会自动更新;反之,当视图发生变化时,模型数据也会同步更新。这种机制可以分为两部分:Model 到 View 的数据传递和 View 到 Model 的数据传递。
在 Backbone 中,Model 到 View 的数据传递可以在 View 中监听 Model 的 change 事件,每当 Model 更新,View 中重新执行 render。而 View 到 Model 的数据传递可以监听 View 对应的 DOM 元素的各种事件,在检测到 View 状态变更后,将变更的数据发送到 Model(通过两边的监听事件)。
三、AngularJS 的双向数据绑定
AngularJS 采用“脏值检测”的方式,数据发生变更后,对于所有的数据和视图的绑定关系进行一次检测,识别是否有数据发生了改变,有变化进行处理,可能进一步引发其他数据的改变,所以这个过程可能会循环几次,一直到不再有数据变化发生后,将变更的数据发送到视图,更新页面展现。如果是手动对 ViewModel 的数据进行变更,为确保变更同步到视图,需要手动触发一次“脏值检测”。
四、VueJS 的双向数据绑定
VueJS 则使用 ES5 提供的 Object.defineProperty() 方法,监控对数据的操作,从而可以自动触发数据同步。并且,由于是在不同的数据上触发同步,可以精确的将变更发送给绑定的视图,而不是对所有的数据都执行一次检测。
在 Vue 中,对于的函数为 defineReactive,在精简版实现中,我只保留了一些基本特性:
function defineReactive(obj, key, value){
var dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactGetter(){
if(Dep.target){
dep.depend();
}
return value;
},
set: function reactSetter(newVal){
if (value === newVal) {
return;
} else {
value = newVal;
//如果数据发生改变,则通知所有的 watcher(借助 dep.notify())
dep.notify();
}
}
})
}
五、数据绑定关系的识别过程
在对数据进行读取时,如果当前有 Watcher(对数据的观察者,watcher 会负责将获取的新数据发送给视图),那将该Watcher 绑定到当前的数据上(dep.depend(),dep 关联当前数据和所有的 watcher 的依赖关系),是一个检查并记录依赖的过程。而在对数据进行赋值时,如果数据发生改变,则通知所有的 watcher(借助 dep.notify())。这样,即便是我们手动改变了数据,框架也能够自动将数据同步到视图。
三种框架的双向数据绑定机制都有其优缺, Vue 的 Object.defineProperty() 方法和 AngularJS 的“脋值检测”方式各有其优点,但 Vue 的方式更为灵活和高效。