首先,什么是双向数据绑定?
数据变化更新视图,视图变化更新数据,即双向数据绑定;
输入框内容变化时,data中的数据同步变化 view=>model
data中的数据变化时,文本节点的内容同步变化 model=>view
设计思想:观察者模式
Vue的双向数据绑定的设计思想为观察者模式。
Dep对象:Dependency依赖的简写,包含有三个主要属性:id,subs,target和四个主要函数addSub,removeSub,depend,notify,是观察者的依赖集合,负责在数据发生改变时,使用notify()触发保存在哎subs下的订阅列表,依次更新数据和DOM。
Observer对象:即观察者,包含两个主要属性value,dep。做法是使用getter、setter方法覆盖默认的取值和赋值操作,将对象封装为响应式对象,每一次调用时更新依赖列表,更新值时触发订阅者,绑定在对象的_ob_原型链属性上。
new Vue({
el:"#app",
data:{
count:100
},
...
})
初始化函数initMixin:
Vue.prototype._init=function(options){
...
var vm=this;
initLifecycle(vm);
initEvents(vm);
initRender(vm);
callHook(vm,'beforeCreate');
// 这里就是我们接下来要跟进的Vue参数
initState(vm);
initInjections(vm);
callHook(vm,'created');
}
初始化参数initState:
function initState(vm){
vm._watchers={};
var opts=vm.$options;
if (opts.props){initProps(vm,opts.props);}
if (opts.methods) { initMethods(vm,opts.methods);}
// 我们的count在这里初始化
if (opts.data){
initData(vm);
}else {
observe(vm._data={},ture};
}
if (opts.computed) { initComputed(vm,opts.computed);}
if (opts.watch) { initWatch(vm,opts.watch);}
}
initData:
function initData(vm){
var data=vm.$options.data;
data=vm._data=typeof data==='function'
? data.call(vm)
: data || {};
if (!isPlainObject(data)){
data={};
}
...
// observe data
observe(data,true );
}
将data参数设置为响应式:
function observe(value,asRootData){
if(!isObject(value)){
return
}
var ob;
if(hasOwn(value,'_ob_')&& value._ob_instanceof Observer){
ob=value._ob_;
}else if{
observerState.shouldConvert &&
!isServerRendering() &&
(Array.isArray(value)||isplainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
){
ob=new Observer(value);
}
if (asRootData && ob){
ob.vmCount++;
}
return ob;
}
Observer类:
(观察者类)
var Observer=function Observer(value){
this.value=value;
this.dep=new Dep();
this.vmCount=0;
def(value,'_ob_',this);
if(Array.isArray(value)){
var augment=hasProto
? protoAugment
:compyAugment;
augment(value,arrayMethods,arryKeys);
this.observeArray(value);
}else{
ths.walk(value)
}
}
observerArray:
Observer.protoype.observeArray=function observeArray(items){
for(var i=0; i=items.length;i<1;i++){
observe(items[i])
}
}
Dep类:
var Dep=function Dep(){
this.id=uid$1++;
ths.subs=[];
}
walk函数:
Observer.prototype.walk=function walk (obj){
var keys=Object.keys(obj)
for(var i=0;i<keys.length;i++){
defineReactive$$1(obj,keys[i],obj[keys[i]])
}
}
vues双向数据绑定所涉及的源码甚多,以上几处只是其中一部分,感兴趣的朋友可以继续钻研vue的源码。