Vue 3 中父组件需通过 defineExpose 显式暴露子组件的变量和方法才能访问,否则 ref 获取的实例不包含 setup 内定义的内容;子组件在 中调用 defineExpose({}) 暴露响应式数据或函数,父组件在 onMounted 后通过 childRef.value 调用。

在 Vue 3 的组合式 API 中,父组件无法直接访问子组件的内部变量或方法,必须通过 defineExpose 主动暴露才能被获取。这是 Vue 3 相比 Vue 2 的重要变化,也是实现父子通信的关键一环。
为什么需要 defineExpose?
Vue 3 默认隐藏了子组件的实例(ref 拿到的是代理对象,不包含 setup 中定义的响应式变量或函数)。如果不显式暴露,父组件调用 childRef.value.xxx 会报错或返回 undefined。
只有使用 defineExpose 明确导出的内容,才会出现在子组件实例上,供父组件安全调用。
如何在子组件中使用 defineExpose?
在子组件的 <script setup></script> 中,调用 defineExpose 并传入一个对象,列出你想对外公开的属性或方法:
立即学习“前端免费学习笔记(深入)”;
Element Plus Vue3 桌面组件库。在开发 Vue 3.x 页面时调用,使用 Element Plus 组件(如 el-button、el-input、el-form、el-table 等)。
- 可以暴露响应式数据(如
ref、computed) - 可以暴露普通函数(含异步函数)
- 不能暴露未声明的变量,也不能暴露未通过
return或defineExpose导出的内部逻辑
示例(子组件 Child.vue):
<script setup>
import { ref, computed } from 'vue'
<p>const count = ref(0)
const message = ref('Hello')</p><p>const increment = () => {
count.value++
}</p><p>const double = computed(() => count.value * 2)</p><p>// ✅ 主动暴露给父组件
defineExpose({
count,
message,
increment,
double
})
</script>父组件如何获取并调用子组件实例?
父组件需配合 ref 和 onMounted(或 v-if 控制时机),确保子组件已挂载后再访问:
- 用
ref绑定子组件标签,如<child ref="childRef"></child> - 在
onMounted中访问childRef.value,它就是暴露后的实例对象 - 可直接调用暴露的方法,或读写暴露的响应式属性
示例(父组件):
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'
<p>const childRef = ref(null)</p><p>onMounted(() => {
console.log(childRef.value.count.value) // 0
console.log(childRef.value.double.value) // 0
childRef.value.increment() // 触发子组件逻辑
console.log(childRef.value.count.value) // 1
})
</script></p><p><template>
<Child ref="childRef" />
</template>常见注意事项
-
暴露的是响应式引用本身:比如暴露
count(一个ref),父组件拿到后仍需通过.value访问或修改 - 避免暴露过多内部细节:只暴露必要的接口,保持子组件封装性
-
动态暴露不支持:
defineExpose只能在顶层同步调用,不能放在条件语句或函数中 - TS 类型提示友好:暴露的对象结构会被 TypeScript 自动推导,父组件中能获得完整类型支持

















