关于Vue.js的响应式原理

开发 前端
Vue.js是一款MVVM框架,上手快速简单易用,通过响应式在修改数据的时候更新视图。Vue.js的响应式原理依赖于Object.defineProperty,尤大大在Vue.js文档中就已经提到过,这也是Vue.js不支持E8 以及更低版本浏览器的原因。

Vue.js响应式原理

写在前面

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

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

在学习过程中,为Vue加上了中文的注释https://github.com/answershuto/learnVue/tree/master/vue-src,希望可以对其他想学习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)呢?

  1. function observer(value) { 
  2.     Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb)) 
  3.  
  4. function defineReactive (obj, key, val, cb) { 
  5.     Object.defineProperty(obj, key, { 
  6.         enumerable: true
  7.         configurable: true
  8.         get: ()=>{ 
  9.             /*....依赖收集等....*/ 
  10.         }, 
  11.         set:newVal=> { 
  12.             cb();/*订阅者收到消息的回调*/ 
  13.         } 
  14.     }) 
  15.  
  16. class Vue { 
  17.     constructor(options) { 
  18.         this._data = options.data; 
  19.         observer(this._data, options.render) 
  20.     } 
  21.  
  22. let app = new Vue({ 
  23.     el: '#app'
  24.     data: { 
  25.         text: 'text'
  26.         text2: 'text2' 
  27.     }, 
  28.     render(){ 
  29.         console.log("render"); 
  30.     } 
  31. })  

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

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

代理

我们可以在Vue的构造函数constructor中为data执行一个代理proxy。这样我们就把data上面的属性代理到了vm实例上。

  1. _proxy(options.data);/*构造函数中*/ 
  2.  
  3. /*代理*/ 
  4. function _proxy (data) { 
  5.     const that = this; 
  6.     Object.keys(data).forEach(key => { 
  7.         Object.defineProperty(that, key, { 
  8.             configurable: true
  9.             enumerable: true
  10.             get: function proxyGetter () { 
  11.                 return that._data[key]; 
  12.             }, 
  13.             setfunction proxySetter (val) { 
  14.                 that._data[key] = val; 
  15.             } 
  16.         }) 
  17.     }); 
  18.  

我们就可以用app.text代替app._data.text了。 

责任编辑:庞桂玉 来源: 染陌同学的博客
相关推荐

2021-01-22 11:47:27

Vue.js响应式代码

2021-04-14 12:47:50

Vue.jsMJML电子邮件

2022-04-17 09:18:11

响应式数据Vue.js

2022-04-16 13:59:34

Vue.jsJavascript

2020-06-09 11:35:30

Vue 3响应式前端

2019-07-01 13:34:22

vue系统数据

2022-04-25 07:36:21

组件数据函数

2013-02-21 09:54:12

响应式重构Web

2023-06-02 16:28:01

2018-04-04 10:32:13

前端JavascriptVue.js

2022-04-05 16:44:59

系统Vue.js响应式

2017-07-04 17:55:37

Vue.js插件开发

2016-11-04 19:58:39

vue.js

2022-05-03 21:18:38

Vue.js组件KeepAlive

2021-09-27 06:29:47

Vue3 响应式原理Vue应用

2020-09-16 06:12:30

Vue.js 3.0Suspense组件前端

2018-07-10 15:35:33

Vue前端架构

2022-04-26 05:55:06

Vue.js异步组件

2022-04-09 17:53:56

Vue.js分支切换嵌套的effect

2022-01-19 22:18:56

Vue.jsVue SPA开发
点赞
收藏

51CTO技术栈公众号