拥抱Vue3 (三) ref 与 reactive以及响应式原理

拥抱Vue3 (三) ref 与 reactive以及响应式原理_第1张图片

一、ref 包装基本数据类型数据

在第二篇文章中举例的时候,我们创建了非响应式的数据,在控制台中查看数据发现并不存在get与set方法。在查了文档后发现,Vue3中需要使用一个新的方法 `ref ` 去让数据变成响应式的。 



话虽这么说,但是为数据添加上 ref 后点击按钮去修改信息,页面上并没有任何变化。为了找到出错的原因,在changeInfo之前先输出name与age试试。

原来经过ref加工后基本数据变成了一个对象,它是Ref(reference)Impl(implement)的实例对象。那我们可以考虑,如何拿到经过ref包装的引用实现的实例对象(即引用对象)中包含的数据。 

拥抱Vue3 (三) ref 与 reactive以及响应式原理_第2张图片

 我们将刚刚打印的内容展开来看,可以清晰的看到被包装的name属性是存在get和set的。如果想读到数据,那么就需要通过.value去获取,修改的话也需要这样。

 function changeInfo () {
    name.value = '白猫',
    age.value = 99
 }

在Vue3中,ref()方法是基于Object.defineProperty与get、set方法去实现的数据劫持。 

二、ref 包装对象数据类型数据

如果想对 ref 包装的数据进行处理,需要对数据.value后再操作,那么对于包装后的对象数据类型数据,也应当需要.value拿到具体对象数据。在Vue2中我们知道,即使一个对象中嵌套了多个对象,Vue都能通过循环遍历,从外到最深处设置响应式。

那么在Vue3中面对一个people对象的时候,我们是否需要在通过people.value拿到实例对象后,继续people.value.name.value去拿到姓名这个属性。





也许在你心中是这么想的:将对象通过 ref 封装后,里面的value也需要进行ref封装,然后获取每一项value的时候都要调用具体的get与set方法。

经过打印后发现,其实是不需要的。通过第一次的.value后,获取对象中的数据便不需要再执行.value这个操作,直接调用即可。

拥抱Vue3 (三) ref 与 reactive以及响应式原理_第3张图片

不必再继续调用.value的原因在于 ref 检测到对象数据类型的数据时,当.value获取到了对象实例本身后,调用了另外一个方法 `reactive` 去包装{}内的数据,该方法是基于Proxy代理实现的。当我们直接用reactive去包裹数据对象的时候甚至可以省略第一个.value。

拥抱Vue3 (三) ref 与 reactive以及响应式原理_第4张图片

三、Vue3响应式原理

在前面介绍过Vue3的ref函数是通过Object.defineProperty去实现响应式的,reactive则是通过proxy来实现。首先介绍一下它的优点

1. 可以直接为对象添加不存在的属性/删除属性

2. 可以直接通过索引下标去修改数组中的元素数据

不难看到,这恰好弥补了Vue2中响应式原理的缺陷https://blog.csdn.net/flow_camphor/article/details/120657910

在这里我们单独创建一个html文件,通过window.proxy去了解一下原理。




    
    
    
    Document


    

在控制台中测试后发现,通过改变p对象中元素的数据后,people中的数据也会得到改变。

拥抱Vue3 (三) ref 与 reactive以及响应式原理_第5张图片

 这样的实现叫做数据劫持,还不能称为响应式。我们接下来需要捕获到这样修改数据的行为。

const p = new Proxy(people,{
    // 读取p身上的某个属性时调用
    get(target,propName){
        // 这里通过[]获取元素的原因在于,Proxy中get方法的第二个参数
        // 返回的是一个字符串,对象无法通过 . 的方式使用字符串
        return target[propName]
    },
    // 修改p身上的某个属性、或者是给p追加某个属性时调用
    set(target,propName,value){
        target[propName] = value
    },
    // 删除p身上某个属性时调用
    deleteProperty(target,propName){
        return delete target[propName]
    }
})

 这样做实现了最为基础的响应式修改,但是这样太简洁了,其实并非Vue3中所使用的方法,接下来我们先看看一个新的知识点Reflect反射。这个是es6中新增的内容,其实现在ECMA正在尝试将Object中的内容全部移植到Reflect中,用Reflect代替Object是一个趋势,对于框架来说,直接通过一个对象去修改数据是可以轻松很多的,因此将上面的代码用Reflect替换。

const p = new Proxy(people,{
    // 读取p身上的某个属性时调用
    get(target,propName){
        return Reflect.get(target,propName)
    },
    // 修改p身上的某个属性、或者是给p追加某个属性时调用
    set(target,propName,value){
        Reflect.set(target,propName,value)
    },
    // 删除p身上某个属性时调用
    deleteProperty(target,propName){
        return Reflect.deleteProperty(target,propName)
    }
})

你可能感兴趣的:(Vue3,vue.js)