详解Vue3的setup语法中defineExpose

我们知道defineExpose是Vue3的setup语法下提供的api,setup语法下组件数据对外是默认关闭的,必须要通过该api暴露后父组件才能调用,那么如果子组件暴露的变量父组件可以通过修改该变量进而改变子组件的变量吗?做了一些测试下面说明。

案例一:

父组件

子组件loginPanel

输出结果为:

可以看到导出的变量a被修改成122,输出loginPanel.value.a也变成122了, 但是b函数确输出了1, 这说明子组件内a变量并没有真正被修改

案例二:

父组件不变,依旧和上一案例一致

子组件的 a = 1 变为 a = ref(1)

输出结果为:

可以看到a被改成122后b函数输出的是RefImpl对象, 当中的值也被改成122了,也就是说 子组件的 a 变量被真正的修改了

为什么两者不一致?

前面说到使用了 setup 后组件数据对外关闭,需要使用 defineExpose 暴露,该 api 暴露的并不是子组件真正实例本身,从输出就可以看到,其暴露的变量和函数都是使用一个新的对象包裹并且通过 Proxy 代理的新对象,输出 loginPanel.value 它是这样的

案例一所以直接通过 loginPanel.value!.a 修改的导出来的被Proxy封装的新对象的 a, 子组件 a 并没有被真正更改;

案例二类推, 直接通过 loginPanel.value!.a 修改的是 a 的 RefImpl对象的value, ref底层使用的Reflect.defineProperty, 该 RefImpl 对象正是子组件 a 变量引用的对象, 故子组件 a 变量的值即 a.value被真正修改。 既然 a 是ref对象,为什么不是 loginPanel.value!.a.value = 122 这样呢, 不用 .value就能直接改? 这就是这里神奇的地方,在setup语法使用defineExpose父组件中使用子组件暴露的ref数据是会自动解包的,不需要 .value, 赋值也不用,因为在修改通过父组件 loginPanel.value!.a = 122 修改的时候,由于loginPanel.value 是Proxy实例,内部做了监听。

最后:这只是个人学习测试好奇,开发中最好不要在父组件中直接修改子组件的数据,并且官方也不推荐这么做,至少要通过暴露的函数形式来修改子组件数据,否则容易造成混乱难以维护,被改了也不知道不能够进行规范约束,要改也要弄个暴露函数内部做监控。

相关推荐
花花鱼1 小时前
@antv/x6 导出图片下载,或者导出图片为base64由后端去处理。
vue.js
流烟默1 小时前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
蒲公英10012 小时前
vue3学习:axios输入城市名称查询该城市天气
前端·vue.js·学习
杨荧5 小时前
【JAVA开源】基于Vue和SpringBoot的旅游管理系统
java·vue.js·spring boot·spring cloud·开源·旅游
一 乐10 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
小御姐@stella11 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
万叶学编程14 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js
积水成江17 小时前
关于Generator,async 和 await的介绍
前端·javascript·vue.js
计算机学姐17 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
老华带你飞17 小时前
公寓管理系统|SprinBoot+vue夕阳红公寓管理系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·spring boot·课程设计