vue中的虚拟dom和双向数据绑定的结合。
vue中的虚拟dom和双向数据绑定的结合。vue1.0中使用Object.defineProperty了双向数据绑定,使用dep进行订阅发布链接watcher和data的桥梁。这时候,一个data页面中用到几处就会在dep中添加几个函数更新相对应的dom。但是vue2.0中结合虚拟dom机制。所以没有所谓的temple中一个指令对应一个dom更新函数。而是一个组件只有一个更新函数为render。这个当数据变化时候,这个函数会对比前后的虚拟dom更新真正需要更新的真实dom。
所以vue2中data的一个变量有3个地方会有对应的watcher
-
一个vm组件会对应一个watcher,这个watcher关注的是vm的_render方法,每个vue文件的template里面的内容都会被编译成一个_render方法,
并且里面用到的属性或者computed都会转化成_vm.name 或者_vm.infoName 的代理形式,具体的转化过程在dep里面说到 -
computed对象里面的每个属性,都有一个对应的watcher,如上例:infoName,infoSex都会有一个对应的watcher,并且生成的watcher的lazy为true,
即它们都是懒更新的,只有里面用到的相关数据出现变化的时候,这个watcher才会执行getter方法 -
watch对象里面的每个属性,都有一个对应的watcher,如上例:sex,name,"resultObj.allInfo"都会有一个对应的watcher
我发现vue2中 对于页面渲染只会 new 一个 Watcher。因为每个Watcher的回调函数都是一样的触发render。在render的时候会遍历data触发所有的get。所有每个data的值的Watcher都是这个Watcher。更新的时候,Watcher的id一样则只更新一个,每个computed或者watch的key都会 new 一个 Watcher。这时候再执行相对应的value,就会触发相应的data的get。对应的data对push刚刚new 的这个 Watcher。
vue2中data的watcher是如何push到对应的dep中的呢?
vue2 中
- 首先会生成render函数
- 执行$mount函数,函数内简易关键代码如下
var updateComponent = function () {
vm._update(vm._render(), hydrating);
};
new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */);
function Watcher (vm,
expOrFn,
cb,
) {
if (typeof expOrFn === 'function') { // expOrFn就为 updateComponent
debugger
this.getter = expOrFn;
} else {
this.getter = parsePath(expOrFn);
if (!this.getter) {
this.getter = function () {};
}
}
this.value = this.lazy // computed 的lazy 才会为true。
? undefined
: this.get(); // 如下段代码
};
}
Watcher.prototype.get = function get () {
pushTarget(this); // Dep.target = this;
var value;
var vm = this.vm;
try {
value = this.getter.call(vm, vm); // 执行了vm._update(vm._render(), hydrating);
} catch (e) {
} finally {
popTarget();// Dep.target = null;
}
return value
};
this.getter.call(vm, vm)
触发了vm._update(vm._render(), hydrating);
所以触发所有的data的get属性,所以所有的data属性都在此时添加了依赖并且是一样的依赖。