欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

深入分析 vue3 响应式和有关设置、反应式、参考资料的详细章节

最编程 2024-03-06 17:28:22
...

前述

11/9 晴

hello,大家周五好,过完今天又迎来一个愉快的双休拉。老样子,开始写文章之前,先来唠唠嗑。可能关注我的小伙伴会发现,我这次更新文章的频率相对而言是很快的。距离上次写,才过去了两周。

为什么要提上更新频次呢?

那就是:拒绝懒惰,想把一件事做好,还是需要坚持呀。还有写文章,不但可以给大家分享,也可以自我巩固和学习。

然后今天要说的内容是需要大家对 vue 有一定了解的哦!

好了,开始今天的正文吧,走起~

正文

vue3响应式

说到 vue3 的响应式,那就先来说下 vue2 的响应式。vue2 中的响应式,直接在 data 中进行数据处理和绑定,return 值,就可以做到了。但是在 vue3 中可以说是大改了 vue2 的处理机制。

vue3 中不再使用 data ,而是改用 setup ,以及 refreactive 的方法来做到响应式。

那么 vue2 中的响应式机制是怎么做的呢?看代码:

    Object.defineProperty(data,'count',{
        get(){},
        set(){}
    })
        

上面这段代码,相信大家都不陌生,getset 进行数据的读取和修改。但就这种方式可以看出,只能对于已有的数据进行这两个操作,且不能满足其他的需求。比方说:

如果我有一个对象。我需要对这个对象添加一个新的属性,或者删除一个已有的属性。上面的方法是不是就不会有作用,也做不到响应式。

再者,如果我有一个数组,我需要把这个数组变成一个响应式的数组,我需要怎么办?是不是就只能重写这个数组,更新这个数组中的一系列需要更新的元素,

再者,如果我是直接通过下标来更新某个元素,会响应式吗?明显也是不会的。所以这也是为什么需要使用 $set() 来对这种情况进行响应式操作。

那么 vue3 ,完完全全就不是像 vue2 中这样玩儿的了。而是通过 Proxy(代理)以及 Reflect(反射),对数据进行监视以及响应式的操作。

在看 vue3 的响应式是怎么做的之前呢,可以先来简单看下这两个方法。ProxyReflect

Proxy

如何去理解 Proxy 呢?官方的术语比较晦涩,其实简单点理解就是一句话:实现数据代理

为了方便,我把语法和相关解释都贴一下:

语法:

const p = new Proxy(target, handler)
  • handler 包含捕捉器(trap)的占位符对象,可译为处理器对象。

  • traps

    提供属性访问的方法。这类似于操作系统中捕获器的概念。

  • target

    被 Proxy 代理虚拟化的对象。它常被作为代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。

这里简单扯一下:target:就是你要代理的目标对象。handler:就是监视你这个目标对象的处理器,它也是个对象,包含多个方法,看需要使用即可。

Reflect

同样,如何去理解 Reflect 呢?也可以简单理解成一句话:就是动态的对被代理的对象进行操作。并且它是配合 Proxy 中的 handler 来一起使用的。

有一个注意点,就是这个方法,不能够实例,也就是不能够 new

哈哈哈哈,感觉说了这么多,还不如来看一段代码实际:

//这边就不写全部的操作细节了,大家可以自己去操作下

// 目标对象
const usr ={
    name:haha,
    age:30,
    child:{
        name:xixi,
        age:18
    }
}

// 代理对象 需要传入两个参数,并且是对象。第一个就是目标对象,第二个就是处理器对象
const pro = new Proxy(usr,{
    // 读取
    get(target, property){
        return Reflect.get(target, property)
    },
    // 修改
    set(target, property,value){
        return Reflect.set(target, property,value)
    }
    // 删除
    deleteProperty(target, property){
        return Reflect.deleteProperty(target, property)
    }
    // ... 其他的方法
})
// 获取对象中的属性
pro.name // haha
pro.child.name // xixi
// 更改对象
pro.name='wawa' // wawa
pro.child.age = 100 // 100
// 新增
pro.score = 98 // 对象usr中新增了一个score属性
// 删除
delete pro.name // 删除了name
detele pro.child.name // 删除了child种的name

要注意一点就是,每个方法中一定要对应 Reflect ,因为它是完成响应式的关键,要是没有它,你所有的操作,都无法作用到目标对象上。

看到这边,小伙伴们有没有想过一个问题,为什么 vue3 的响应式要变?

可能有小伙伴会说,啊,vue2 中的 datareturn ,那么方便,现在搞到 vue3 中,还要 setupreactiveref。这不是繁琐操作了吗?

为什么呢?小伙伴们可以看到 vue2 中是通过 Object.defineProperty,的方式实现响应式。那么这个有什么弊端呢?可以简单的思考几分钟。

答案就是:Object.defineProperty 这种形式,会给对象中的每个属性都加上一个 getset 方法来达到响应式的目的。那么这个其实就会带来开销的问题。

简单点说:如果某个对象下面有n个属性,那么是不是就要开辟2倍的n 的 getset。所以这样做的弊端是可想而知。

而在 vue3 中,只需要一个代理对象,一个 Reflect 对象,就可以实现响应式,并且没有额外的开销。而且,在上面的举例中,可以看到,这种代理是深度代理,就是响应式,不仅可以响应一级属性,甚至可以响应多集属性,这也就解释了,为什么 reactive({}),是深度代理。(当然也有浅代理的方法,今天不讲这块儿)。

好了,响应式说完,那就聊聊关于 setuprefreactive 的一些细节。

setup

生命周期

setup 是在 BeforeCreate 之前执行的,这个在 vue3 的生命周期中写的很清楚,那么这里需要注意什么呢?

就是说,在 setup 执行的时候,组件还没有创建,那么就是还没有实例化,是不是就说明, this 这个时候,还是 undefined

答案是的。小伙伴可以去生命周期中,console.log看一下便知了。

合并

vue3 中是可以写 vue2 中的代码,这个小伙伴肯定都知道,那么如果一个 vue 文件中,既有 vue3setup 又有 vue2datamethods 的话,会怎么样呢?

这不简单吗。写段代码看下不就知道了吗:

    setup(){
        const a =10 ;
        const aaa = ()=>{
            console.log('hhhhhh')
        }
        return{
            a,
            aaa
        }
    },
    
    data(){
        return {
         b:20
        }
    },
    
    methods:{
        bbb(){
            console.log('xixixixi')
        }
    },
    
    mounted(){
        console.log(this) // 打印看看
    }
    
    // console输出:
    Proxy:Object
    handler:Object
    Target:{
        a:10,
        b:20,
        aaa(),
        bbb()
    }
    

看到这,相信小伙伴就知道了,那就是,如果 vue 文件中既有 vue3 的代码,又有 vue2 的代码,那么就会被合并成一个组件对象属性,统一交给 Proxy 代理对象。

说到这,可能小伙伴要笑了,那我就写个 setup ,其他都用 data 来做,岂不是美哉。哈哈哈哈,我没试过,有想法的可以试试。

还有就是 setup 本事就是 return,所以不能用异步,也就是说像 async steup(){} ,这样,因为异步返回的就是 promise 了。所以是不可以的。

好了,关于 setup 相关的就说这么多,接下来简单说下,refreactive

ref & reactive

关于 refreactive 小伙伴们可能都知道,一个是处理数据,一个是处理对象,但其实 ref 也可以处理对象。只不过在调用的时候,需要使用 .value 的方式来对数据进行操作。

并且 ref 中如果是放入了对象,那就会经过 reactive 的处理,生成 proxy 代理对象。这个代理也是深度代理。嵌套层级再多也可以。

这里的代码演示也很简单,只需要定义再去console.log 看一下就可以了

    const a = ref(1)
    const aa = ref({name:'haha',age:18})
    const aaa = reactive({score:88})
    
    console.log(a,aa,aaa)
    
    // 打印结果
    aa中会存在Proxy:Object

关于这块也就这么多啦,嘿嘿,最后,留一个小问题,给大家思考一下。往下看????

template模板

为什么vue3中的vue文件中不要求,一定要在template中写上div根标签呢?

可以评论区告诉我~

结语

以上就是本期说的内容啦,要是有说的不对的地方,还请指出。

然后关于上一篇文章呢,说到遇到了瓶颈期。其实现在也想通了,好好做自己的事情,踏踏实实的做好自己的事情,一切交给机会和缘分。

好啦,这期就说到这咯,要是有小伙伴想听其他的,也可以留言。

嘿嘿~ 拜拜~