写在前面
因为对 Vue.js 很感兴趣,而且平时工作的技术栈也是 Vue.js,这几个月花了些时间研究学习了一下 Vue.js 源码,并做了总结与输出。
文章的原地址:answershuto/learnVue。
在学习过程中,为 Vue 加上了中文的注释 answershuto/learnVue,希望可以对其他想学习 Vue 源码的小伙伴有所帮助。
可能会有理解存在偏差的地方,欢迎提 issue 指出,共同学习,共同进步。
关于 Vue.js
Vue.js 是一款 MVVM 框架,上手快速简单易用,通过响应式在修改数据的时候更新视图。Vue.js 的响应式原理依赖于 Object.defineProperty,尤大大在 Vue.js 文档中就已经提到过,这也是 Vue.js 不支持 E8 以及更低版本浏览器的原因。Vue 通过设定对象属性的 setter/getter 方法来监听数据的变化,通过 getter 进行依赖收集,而每个 setter 方法就是一个观察者,在数据变更的时候通知订阅者更新视图。
将数据 data 变成可观察(observable)的
那么 Vue 是如何将所有 data 下面的所有属性变成可观察的(observable)呢?
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)。
那么问题来了,需要对 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 了。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于