vue监测数据的原理

概要:

Vue实例化对象挂载到根元素后,生成全局Vue对象实例,Vue对象在实例化过程中会传入配置对象(options),options中包括data、methods、computed、watch等等。至于Vue是如何对data中数据的变化进行监测的,原理大致如下:

一、普通数据监测原理及步骤

1. data对象加工成_data对象,并存入Vue实例

data对象的加工处理过程:递归为每一个非对象类型的数据添加响应式的get、set方法(reactive getter、reactive setter)(数据劫持:指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。vue中将data经过加工处理变为_data,data中含有getter、setter的这一过程就是数据劫持。)

非对象类型:


data:{
        key1:value1,           //key1为非对象类型数据
        key2:{                 //key2为对象类型数据
            key3:value3,       //key3为非对象类型数据
            key4:{             //key4为对象类型数据
                key5: value5,  //key5为非对象类型数据
            },
        }
    }

如何添加 reactiveGetter() (reactive响应式) 和reactiveSetter(newVlaue): 使用数据代理(所谓数据代理,就是通过一个对象代理对另一个对象中属性的操作【读/写】。数据代理是使用原生JS的Object.defineProperty()方法实现的。)

       

        下面这段代码只是一个简单的vue的响应式getter和setter的实现原理,这段代码只能实现单层属性的响应式getter和setter,一但data中存在上面一段中的嵌套结构,则不能为第二层、第三层等属性添加getter()和setter()。在实际的vue中要比这段代码更为复杂,vue在底层中写了一个递归,data有多少层,vue就会向下找多少层,直到最后是非对象类型为止。

let data = {
        key1:value1,
        key2:value2,
    }

    // 创建一个观察者实例对象,用于监测data中属性的变化
    const obs = new Observer(data)
    
    //准备一个实例对象vm
    const vm = {}
    vm._data = data = obs

    function Observer(obj){
        // 汇总obj中所有属性,形成一个数组keys
        const keys = Object.keys(obj)
        // 遍历keys数组(此处为简化示例,未体现属性是一个对象或一个数组进行递归的情况)
        keys.forEach((key)=>{
            //这里的 this 指向的是new的实例对象obs,给Observer的实例对象添加属性 
            Object.defineProperty(this,key,{
                get(){
                    return obj[key]
                },
                
                set(value){
                    obj[key] = value
                }
            })
        })
    }

2. vue全局实例对象代理_data对象,实现对_data中属性的直接操作

对data加工生成_data对象,并存入vue实例对象后,vue实例对象会通过数据代理的方式,对_data对象进行代理,为每个对象设置getter和setter,从而实现通过this.key1 = new_value1 以及 const value = this.key1 的形式,直接对_data中的key1进行修改和读取。

3. 数据变化监测效果

每个具有reactiveSetter()的数据发生变化时,都会调用这个reactiveSetter(),而这个reactiveSetter() 被调用时,会触发重新解析模板、生成新的虚拟DOM,新旧虚拟DOM对比,更新内容映射到真实DOM,重新渲染这一套流程。

 二、动态新增可被监测的属性 Vue.set()或this.$set()

由于JavaScript的限制,Vue无法检测到后续在data的数组和对象中添加新的属性的变化,因此也不会触发视图更新。

1.对于对象

Vue 无法监测data中不存在的属性的添加或移除。由于 Vue 会在初始化实例时对 data的属性执行 getter/setter 转化,所以属性必须在 data 对象上存在才能让 Vue 将它转换为响应式的。

var vm = new Vue({
  data:{
    a:1
  }
})

vm.a=2 
v.a    // 是响应式的

vm.b = 2
vm.b   // 是非响应式的,vue监测不到

使用方法: Vue.set(target,key,value)    this.$set(target,key,value)

注意:Vue不允许动态添加根级响应式属性。【 Vue.set()只能给data中的某一对象追加属性,而不能给data追加属性。】

2.对于数组

Vue不会为数组元素添加响应式的getter和setter,(即使data中原来存在的数组也不会为其添加getter和setter),所以通过数组的索引值更改数组数据无法被Vue监测到。

(1) 只有调用了数组对应的7个更改数组的方法:push()pop()shift()unshift()splice()reverse()sort()这7个改变原数组本身的API,才会引起Vue的响应。

(2) Vue.set(target,key,value)    this.$set(target,key,value)

总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值