遇见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是如何实现这个过程

image

Vue.js在这里主要做了三件事:

image

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方法对模板进行编译。

image

。。。待更新compile

Watcher