详解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实例,内部做了监听。

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

相关推荐
莫物13 小时前
vue过滤表格数据导致的索引错乱问题
前端·javascript·vue.js
Можно14 小时前
Vue 组件样式隔离完全指南:从原理到实战
前端·javascript·vue.js
英俊潇洒美少年14 小时前
Vue3 完整渲染流程(从 createApp → mount → update → unmount)
前端·javascript·vue.js
前端Hardy14 小时前
Pinia 比 Vuex 好用 10 倍?Vue3 状态管理终于不折磨人了!(新手复制即用)
前端·javascript·vue.js
前端Hardy14 小时前
Vue3 的 v-model 双向绑定,90% 的人都用错了?(附 2026 最新避坑指南)
前端·javascript·vue.js
前端Hardy14 小时前
救命!Vue3 的 Composition API,居然能让我少写 80% 冗余代码?(新手也能直接抄)
前端·javascript·vue.js
王霸天15 小时前
🚨 还在用 rem) 做大屏适配?用 vfit.js 一键搞定,告别改稿8版的噩梦!
前端·vue.js·数据可视化
Mr Xu_16 小时前
Vue3 + Leaflet实战:深入解析MarkerCluster点位聚合插件的使用与优化
前端·javascript·vue.js
源码宝16 小时前
使用 PHP(Laravel 8)+ Vue 2 + Element UI + MySQL 5.7开发一套医院不良事件系统的注意事项
vue.js·php·laravel
D_C_tyu16 小时前
Vue + Leaflet 实现地图任意点位点击查看时间功能
前端·javascript·vue.js