Vue.js响应式原理

写在前面

由于对Vue.js很感兴趣,并且平时工做的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并作了总结与输出。javascript

文章的原地址:https://github.com/answershuto/learnVuehtml

在学习过程当中,为Vue加上了中文的注释https://github.com/answershuto/learnVue/tree/master/vue-src,但愿能够对其余想学习Vue源码的小伙伴有所帮助。vue

可能会有理解存在误差的地方,欢迎提issue指出,共同窗习,共同进步。java

关于Vue.js

Vue.js是一款MVVM框架,上手快速简单易用,经过响应式在修改数据的时候更新视图。Vue.js的响应式原理依赖于Object.defineProperty,尤大大在Vue.js文档中就已经提到过,这也是Vue.js不支持E8 以及更低版本浏览器的缘由。Vue经过设定对象属性的 setter/getter 方法来监听数据的变化,经过getter进行依赖收集,而每一个setter方法就是一个观察者,在数据变动的时候通知订阅者更新视图。react

将数据data变成可观察(observable)的

那么Vue是如何将全部data下面的全部属性变成可观察的(observable)呢?git

function observer(value) {
    Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}

function defineReactive (obj, key, val, cb) {
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: ()=>{
            /*....依赖收集等....*/
        },
        set:newVal=> {
            cb();/*订阅者收到消息的回调*/
        }
    })
}

class Vue {
    constructor(options) {
        this._data = options.data;
        observer(this._data, options.render)
    }
}

let app = new Vue({
    el: '#app',
    data: {
        text: 'text',
        text2: 'text2'
    },
    render(){
        console.log("render");
    }
})

为了便于理解,首先考虑一种最简单的状况,不考虑数组等状况,代码如上所示。在initData中会调用observe这个函数将Vue的数据设置成observable的。当_data数据发生改变的时候就会触发set,对订阅者进行回调(在这里是render)。github

那么问题来了,须要对app._date.text操做才会触发set。为了偷懒,咱们须要一种方便的方法经过app.text直接设置就能触发set对视图进行重绘。那么就须要用到代理。数组

代理

咱们能够在Vue的构造函数constructor中为data执行一个代理proxy。这样咱们就把data上面的属性代理到了vm实例上。浏览器

_proxy(options.data);/*构造函数中*/

/*代理*/
function _proxy (data) {
    const that = this;
    Object.keys(data).forEach(key => {
        Object.defineProperty(that, key, {
            configurable: true,
            enumerable: true,
            get: function proxyGetter () {
                return that._data[key];
            },
            set: function proxySetter (val) {
                that._data[key] = val;
            }
        })
    });
}

咱们就能够用app.text代替app._data.text了。app

关于

做者:染陌

Email:answershuto@gmail.com or answershuto@126.com

Github: https://github.com/answershuto

Blog:http://answershuto.github.io/

知乎专栏:https://zhuanlan.zhihu.com/ranmo

掘金: https://juejin.im/user/58f87ae844d9040069ca7507

osChina:https://my.oschina.net/u/3161824/blog

转载请注明出处,谢谢。

欢迎关注个人公众号

img

相关文章
相关标签/搜索