Vue3 defineExpose到底是啥?怎么用?为啥子ref拿到子组件是空对象?
最近接触Vue3的新手,十个有九个半都会问这个三连问——先是对着子组件用ref或者$refs拿不到数据/方法挠头,搜一下知道了defineExpose,写了之后又忘写语法糖之外的注意事项,或者不知道什么时候该用什么时候不该用,甚至搞混了它和props、emit的边界,今天就把这些问题揉碎了讲明白,连踩过的坑都给你列得清清楚楚。
defineExpose出现的背景:Vue3和Vue2在组件通信上的一个小变化
Vue3为啥突然加了个defineExpose?其实不是无中生有,而是对Vue2通信方式的“规范化收紧”。
Vue2怎么拿子组件的私有内容?
在Vue2里,不管你子组件愿不愿意,父组件只要绑了ref,就能直接访问到子组件的data、methods、computed,甚至生命周期钩子——听起来是方便,但这种“全开放”的设计其实挺危险的,想想看:子组件里有个data叫_internalCount,本来是用来做内部状态过渡的临时变量,结果父组件直接修改它,某天你重构子组件把这个变量名改了,或者逻辑变了,父组件直接就崩了,而且查错还麻烦得很,因为谁知道哪些外部组件偷偷用了你的私有属性?
Vue3的改进思路
Vue3的设计团队更强调“组件封装性”,所以默认情况下,子组件是完全封闭的——父组件用ref拿到的只是个带$el的空代理对象,只能访问你显式暴露出来的内容,这个显式暴露的API,就是defineExpose。
defineExpose到底是个啥东西?
先给个简单的定义:defineExpose是Vue3 <script setup>语法糖里的一个内置宏(不用导入就能用的函数替代品,编译阶段会被替换成标准代码),或者是普通 <script> 写法里setup()函数的一个入参里的方法,核心作用就是主动选择要暴露给父组件(或者其他通过ref访问子组件的组件)的变量和函数。
注意这里的重点:
- 内置宏/setup入参:看你用不用
<script setup>,用法不一样,后面会分情况说; - 主动选择、显式暴露:你不说,父组件绝对碰不到;
- 父组件通过ref/v-model绑定的组件实例访问:defineExpose不是用来跨层级或者跨兄弟组件通信的,边界很明确,父子(或者通过模板引用连接的任意组件)之间的实例级通信”。
怎么用defineExpose?分两种主流写法
现在Vue3开发基本都用 <script setup> 了,但也有老项目或者习惯用普通组合式API写法的,两种都讲。
code前端网