vue响应式原理

将data下边所有的属性变成可观察的 - observable

Vue.js是一款MVVM框架。怎么做到更改数据时,驱动视图刷新的呢。

总体来说: Vue通过设定对象属性的 setter/getter 方法来监听数据的变化,通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。

这个函数将Vue的数据设置成observable的。当_data数据发生改变的时候就会触发set,对订阅者进行回调(在这里是render)

js 复制代码
function observe(value, cb) {
    Object.keys(value).forEach((key) => 
        defineReactive(value, key, value[key] , cb)
    )
}

function defineReactive (obj, key, val, cb) {
    Object.defineProperty(obj, key, {
        //但是默认是不可枚举的(for in打印打印不出来),可:enumerable: true
        //默认不可以修改,可:wirtable:true     
        //默认不可以删除,可:configurable:true
        
        enumerable: true,
        configurable: true,
        get: ()=>{
            /*....依赖收集等....*/
            return val
        },
        set:newVal=> {
            val = newVal;
            cb(); /*订阅者收到消息的回调*/
        }
    })
}

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

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

这样也存在一个问题,我们需要对app._data.text才能触发数据的set。我们可以做一个代理,做到通过app.text直接设置就能触发set对视图进行重绘通。

代理

我们可以在Vue的构造函数constructor中为data执行一个代理

javascript 复制代码
_proxy.call(this, 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;
            }
        })
    });
}

总结

不考虑数组情况,一个简单的响应式原理就是这样。遍历data下所有属性,通过 defineProperty 劫持到数据的get和set方法,在set数据时,回调runder函数。实现视图刷新。同时需要 _proxy代理_data上的数据到app上。

javascript 复制代码
function observe(value, cb) {
  Object.keys(value).forEach((key) => 
      defineReactive(value, key, value[key] , cb)
  )
}
function defineReactive (obj, key, val, cb) {
    Object.defineProperty(obj, key, {
        //但是默认是不可枚举的(for in打印打印不出来),可:enumerable: true
        //默认不可以修改,可:wirtable:true     
        //默认不可以删除,可:configurable:true
        
        enumerable: true,
        configurable: true,
        get: ()=>{
            /*....依赖收集等....*/
            return val
        },
        set:newVal=> {
            val = newVal;
            cb(); /*订阅者收到消息的回调*/
        }
    })
}

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;
          }
      })
  });
}

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

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

app.text = '22'
console.log(app)
相关推荐
wow_DG1 小时前
【Vue2 ✨】Vue2 入门之旅 · 进阶篇(九):Vue2 性能优化
javascript·vue.js·性能优化
一 乐2 小时前
美食分享|基于Springboot和vue的地方美食分享网站系统设计与实现(源码+数据库+文档)
java·vue.js·spring boot·论文·毕设·美食·地方美食分享网站系统
我是日安3 小时前
从零到一打造 Vue3 响应式系统 Day 4 - 核心概念:收集依赖、触发更新
前端·vue.js
wow_DG4 小时前
【Vue2 ✨】Vue2 入门之旅 · 进阶篇(八):Vuex 内部机制
前端·javascript·vue.js
若年封尘4 小时前
吃透 Vue 样式穿透:从 scoped 原理到组件库样式修改实战
前端·javascript·vue.js·样式穿透·scoped
前端码农.4 小时前
Element Plus 数字输入框箭头隐藏方案
前端·vue.js
GDAL6 小时前
为什么Cesium不使用vue或者react,而是 保留 Knockout
前端·vue.js·react.js
芜青6 小时前
【Vue2手录11】Vue脚手架(@vue_cli)详解(环境搭建+项目开发示例)
前端·javascript·vue.js
麦麦大数据8 小时前
J002 Vue+SpringBoot电影推荐可视化系统|双协同过滤推荐算法评论情感分析spark数据分析|配套文档1.34万字
vue.js·spring boot·数据分析·spark·可视化·推荐算法
BillKu12 小时前
Vue3 + Element-Plus 抽屉关闭按钮居中
前端·javascript·vue.js