Vue3响应式原理

vue共使用了三种响应式机制:defineProperty、Proxy、value setter

1.defineProperty【Vue2】

对象类型:通过object.defineProperty()对属性的读取、修改进行拦截(数据劫持)

数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)


let getDouble = n=>n*2
let obj = {}
let count = 1
let double = getDouble(count)

Object.defineProperty(obj,'count',{
    get(){
        return count
    },
    set(val){
        count = val
        double = getDouble(val)
    }
})
console.log(double)  // 打印2
obj.count = 2
console.log(double) // 打印4  有种自动变化的感觉

缺陷:对象新增属性、删除属性&&通过下标修改数组,界面不会自动更新

但也提供了以下属性来新增属性等......

// 对象新增属性
this.$set(this.person, sex, '女')
Vue.set(this.person, sex, '女') //使用Vue时需要导入一下import Vue from 'vue'

// 对象删除属性
this.$delete(this.person, sex)
Vue.delete(this.person, sex) 

// 通过下标更新数组
this.$set(this.person.hobby, 0, '逛街')
this.person.hobby.splice(0, 1, '逛街')

优势:兼容性 

2.Proxy【Vue3 reactive】

模拟vue3中实现响应式: 

Reflect反射对象是es6的,object的一些属性基本它都有,这里是使用Reflect对源对象属性进行操作 Reflect介绍


let proxy = new Proxy(obj,{
    // 读取
    get : function (target,prop) {
        // return target[prop]
        return Reflect.get(target, prop)
    },
    // 修改和新增
    set : function (target,prop,value) {
        // target[prop] = value;
        Reflect.set(target, prop, value)
    },
    // 删除
    deleteProperty(target,prop){
       // return delete target[prop]
        return Reflect.deleteProperty(target, prop)
    }
})

Proxy 的重要意义在于它解决了 Vue 2 响应式的缺陷。我们看代码,在其中我们通过 new Proxy 代理了 obj 这个对象,然后通过 get、set 和 deleteProperty 函数代理了对象的读取、修改&&新增 和删除操作,从而实现了响应式的功能。

Proxy 是针对对象来监听,而不是针对某个具体属性,所以不仅可以代理那些定义时不存在的属性,还可以代理更丰富的数据结构,比如 Map、Set 等,并且我们也能通过 deleteProperty 实现对删除操作的代理。

优势:基于Proxy实现真正的拦截

缺陷:兼容不了IE11,所以项目有对兼容性有要求的就用不了Vue3

应用:Vue3复杂数据结构

Vue 3 的 reactive 函数可以把一个对象变成响应式数据,而 reactive 就是基于 Proxy 实现的。我们还可以通过 watchEffect,在 obj.count 修改之后,执行数据的打印。


import {reactive,computed,watchEffect} from 'vue'

let obj = reactive({
    count:1
})
let double = computed(()=>obj.count*2)
obj.count = 2

watchEffect(()=>{
    console.log('数据被修改了',obj.count,double.value)
})

3.value setter(Vue3 ref)


let getDouble = n => n * 2
let _value = 1
double = getDouble(_value)

let count = {
  get value() {
    return _value
  },
  set value(val) {
    _value = val
    double = getDouble(_value)

  }
}
console.log(count.value,double)
count.value = 2
console.log(count.value,double)

利用对象的 get 和 set 函数来进行监听,这种响应式的实现方式,只能拦截某一个属性的修改,这也是 Vue 3 中 ref 这个 API 的实现。在代码中,我们拦截了 count 的 value 属性,并且拦截了 set 操作,也能实现类似的功能。

优势:实现简单

缺陷:只拦截了value属性

应用:Vue3简单数据结构

举个例子:

在下面的代码中,我们把对图标的对应修改的操作封装成了 useFavicon 函数,并且通过 ref 和 watch 的包裹,我们还把小图标变成了响应式数据。


import {ref,watch} from 'vue'
export default function useFavicon( newIcon ) {
    const favicon = ref(newIcon)

    const updateIcon = (icon) => {
      document.head
        .querySelectorAll(`link[rel*="icon"]`)
        .forEach(el => el.href = `${icon}`)
    }
    const reset = ()=>favicon.value = '/favicon.ico'

    watch( favicon,
      (i) => {
        updateIcon(i)
      }
    )
    return {favicon,reset}
  } 

这样一来,在组件中,我们就可以通过响应式的方式去修改和使用小图标,通过对 faivcon.value 的修改就可以随时更换网站小图标。

实现:在点击按钮之后,修改了网页的图标为 geek.png 的操作。


 <script setup>
 import useFavicon from './utils/favicon'
 let {favicon}  = useFavicon()
 function loading(){
   favicon.value = '/geek.png'
 }
</script>

<template>
  <button @click="loading">123</button>
</template>

VueUse工具包:将开发常见的属性封装为了响应式函数

安装、


npm install @vueuse/core

在下面这段代码中,我们使用 useFullscreen 来返回全屏的状态和切换全屏的函数。这样,我们就不需要考虑浏览器全屏的 API,而是直接使用 VueUse 响应式数据和函数就可以很轻松地在项目中实现全屏功能。


<template>
  <h1 @click="toggle">click</h1>
</template>
<script setup>
import { useFullscreen } from '@vueuse/core'
const { isFullscreen, enter, exit, toggle } = useFullscreen()
</script>

 useFullscreen 的封装逻辑和 useStorage 类似,都是屏蔽了浏览器的操作,把所有我们需要用到的状态和数据都用响应式的方式统一管理,VueUse 中包含了很多我们常用的工具函数,我们可以把网络状态、异步请求的数据、动画和事件等功能,都看成是响应式的数据去管理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值