当前位置: 首页 > news >正文

6.原始值的响应式方案

前言

原始值是指js中的基础数据类型

Boolean,Number,BigInt,String,undefined,null。在js中,原始值是按照值本身传递的,而不是靠引用传递的,一个函数接受原始值,形参和实参之间没有引用关系,是完全独立的值,修改形参不会对实参有任何影响。

Proxy只能代理引用类型,无法代理原始值,因此想要将原始数据变为响应式数据,需要在外面套上一层。

在vue3中,我们定义一个字符串,数字类型的响应式数据,都是用ref(xxx)去定义的。

1.引入ref概念

封装一个ref函数

//最基础的ref函数
const ref = (val)=>{//创建一个包裹对象const proxyObj = {value:val}//将这个包裹对象返回出去,作为一个响应式的对象return reactive(proxyObj)
}

问题1:区别是否为ref创建

const a1 = ref('wjt')
const a2 = reactive({value:'wjt'})

从上帝视角看,我们可以分清楚a1和a2谁是ref创建的,但是在reactive函数中,确实无法判断。因为两个值都是{value:‘wjt’}

解决方法:在ref函数中,给定一个标识,让reactive知道这个对象是ref创建出来的

但是有一点,这个标识是不可以枚举的,也就是只能看不能写的。就好比一个人的性别,你只能去知道,不能去修改。

//给ref增加标识
const ref = (val)=>{const proxyObj = {value:val}//给proxyObj对象身上定义一个不可枚举的标识属性isRef,值为trueObject.defineProperty(proxyObj,'__isRef__',{value:true})return reactive(proxyObj)
}

2.响应丢失问题

vue中有这样的场景

<template><div>{{text}}</div>
</template>
<script>export default{setup(){const text = reactive({value:1})setTimeout(() => {text.value = 2},100);return{...text}}}
</script>

响应式数据的丢失,实则是展开运算符,也就是…text导致的。

return {
...obj
}
//等同于
return {value:1
}

也就是说return{…text},就返回了一个新的普通对象newObj,而不是响应式对象

问题:副作用函数内访问的是普通对象,没有响应能力。现在需要做的,就是在副作用函数内,即使通过普通对象来访问newObj,也能够建立联系。

//定义方法toRef,让一个普通对象变成响应式对象
const toRef = (obj,key)=>{const wrapper = {get value(){   //通过get方法去拦截普通对象的读取操作,指向obj[key]return obj[key]}}return wrapper}//不过一次只写一个key,对于对象内多个属性就不方便了,可以定义一个toRefs,让所有的属性都可以变成响应式的
const toRefs = (obj)=>{const ret = {}//使用for...in循环对象,逐个调用toRef方法for(const key in obj){ret[key] = toRef(obj,key)}return ret}

目前还存在两个问题:

1.为了让reactive方法知道这个对象通过toRef函数调用后已经变成了响应式的数据,需要添加isRef的标识

2.因为只给toRef定义了get方法,如果进行set操作时,又不具备触发副作用函数的操作,这里还需要再加上set

const toRef = (obj,key)=>{const wrapper = {get value(){   //通过get方法去拦截普通对象的读取操作,指向obj[key]return obj[key]},set value(val){  //设置set方法obj[key] = val}}Object.defineProperty(wrapper,'__isRef',{  //添加isRef的标识value:true})return wrapper}

3.自动脱ref

假设一个对象obj是个响应式对象,需要obj.value才能获取值,但是在模板中,我们不需要{{obj.value}},只需要{{obj}}就能获取到值,是因为对ref生成的对象都做了一层处理,让用户不需要.value就可以方便的用

const proxyRefs = (target)=>{return new Proxy(target,{get(target,key,receiver){const value = Reflect.get(target,key,receiver)//如果是ref处理的数据,将value.value抛出;如果不是,就是直接抛出valuereturn value.__isRef__?value.value:value},set(target,key,newValue,receiver){const value = target[key]if(value.__isRef){value.value = newValuereturn true}return Reflect.set(target,key,newValue,receiver)}})
}const newObj = proxyRefs({...toRefs(obj)})

4.总结

1727314491521

http://www.dtcms.com/a/264451.html

相关文章:

  • UniApp 加载 Web 页面完整解决方案
  • UniApp(vue3+vite)如何原生引入TailwindCSS(4)
  • YOLOv11深度解析:Ultralytics新一代目标检测王者的创新与实践(附网络结构图+训练/推理/导出全流程代码详解)
  • 【Erdas实验教程】024:遥感图像辐射增强(亮度反转Brightness Inversion)
  • Python数据解析与图片下载工具:从JSON到本地文件的自动化流程
  • springboot使用redisTemplate的方法,详细说明
  • 以智能楼宇自动化控制系统为基石,构筑绿色建筑节能增效新标杆
  • cmake笔记
  • 【分明集合】特征函数、关系与运算
  • 【格与代数系统】格与哈斯图
  • 笨方法学python-习题12
  • Sql注入中万能密码order by联合查询利用
  • 应急响应类题练习——玄机第四章 windows实战-emlog
  • Foundation 5 安装使用教程
  • SQL SELECT 语句
  • 在线租房平台源码+springboot+vue3(前后端分离)
  • 应急响应类题练习——玄机第五章 Windows 实战-evtx 文件分析
  • 6.Docker部署ES+kibana
  • Vite 7.0 与 Vue 3.5:前端开发的性能革命与功能升级
  • 【环境配置】Neo4j Community Windows 安装教程
  • HDMI 2.1 FRL协议的流控机制:切片传输(Slicing)和GAP插入
  • LL面试题11
  • 10授权
  • Vue 3 中的 `h` 函数详解
  • Rust征服字节跳动:高并发服务器实战
  • 飞算智造JavaAI:智能编程革命——AI重构Java开发新范式
  • Windows10/11 轻度优化 纯净版,12个版本!
  • 深度学习常见的激活函数
  • 【Python基础】11 Python深度学习生态系统全景解析:从基础框架到专业应用的技术深度剖析(超长版,附多个代码及结果)
  • 【深度学习1】ModernBert学习