遇见Vue.js
- 关键词:Vue.js – 读书笔记
十九、Vue.js 源码 深入响应式原理
Vue.js是一个典型的MVVM框架,模型(Model)只是普通的JavaScript对象,修改它则视图(View)会自动更新。
如何追踪变化
<div id="main">
<h1>count:}</h1>
</div>
<script>
var vm = new Vue({
el: "#main",
data: function () {
return{
times: 1
};
},
created: function () {
var me = this;
setInterval(function () {
me.times++;
}, 1000);
}
})
</script>
//Model就是data方法返回的{times:1}
//View是最终在浏览器中显示的DOM
//模型通过Observer/Dep/Watcher/Directive等一系列对象的关联,最终和视图建立起关系
Vue.js是如何实现这个过程
Vue.js在这里主要做了三件事:
Observer
1.Vue.js是如何给data对象添加Observer的。
Vue实例创建的过程会有一个生命周期,其中一个过程就是调用vm._initData方法处理data选项。
在_initData中我们要特别注意_proxy方法,它的功能就是遍历data的key,把data上的属性代理到vm实例上。
_proxy方法主要通过Object.defineProperty的getter和setter方法实现代理。
在_initData方法的最后,调用了observe(data, this)方法来对data做监听。
Observer类的构造函数主要做了这么几件事:
首先创建了一个Dep对象实例,然后把自身this添加到value的__ob__属性上,最后对value的类型进行判断,如果是数组则观察数组,否则观察单个元素。
observeArray方法就是对数组进行遍历,递归调用observe方法,最终都会调用walk方法观察单个元素。
walk方法是对obj的key进行遍历,依次调用convert方法,对obj的每一个属性进行转换,让它们拥有getter、setter方法。只有当obj是一个对象时,这个方法才能被调用。
convert方法调用了defineReactive方法。这里this.value就是要观察的data对象,key是data对象的某个属性,val则是这个属性的值。defineReactive功能是把要观察的data对象的每个属性都赋予getter和setter方法。
defineReactive方法最核心的部分就是通过调用Object.defineProperty给data的每个属性添加getter和setter方法。
当data的某个属性被访问时,则会调用getter方法,判断当Dep.target不为空时调用dep.depend和childObj.dep.depend方法做依赖收集。
当改变data的属性时,则会调用setter方法,这时调用dep.notify方法进行通知。
Dep类是一个简单的观察者模式的实现
export default function Dep(){
this.id = uid++;
this.subs = [];
}
Dep.target = null;
//初始化了id和subs,其中subs用来存储所有订阅它的Watcher
//Dep.target表示当前正在计算的Watcher,它是全局唯一的,因为同一时间只能有一个Watcher被计算
前面提到了dep.depend方法和dep.notify方法:
Dep.prototype.depend = function(){
Dep.target.addDep(this);
}
Dep.prototype.notify = function(){
var subs = toArray(this.subs);
for(var i = 0, l = subs.length; i < l; i++){
subs[i].update();
}
}
Directive
Vue实例创建的生命周期,在给data添加Observer之后,有一个过程是调用vm._compile方法对模板进行编译。
。。。待更新compile