defineexpose 是 vue 3 中的编译时宏,用于显式声明子组件向父组件暴露的方法和响应式状态,必须在顶层使用,支持暴露函数、ref、computed 等,父组件通过 ref.value 调用。

在 Vue 3 的 Composition API 中,setup 函数默认不会暴露任何内容给父组件(比如子组件的 ref、方法等),必须显式使用 defineExpose 才能让父组件通过 ref 访问到子组件内部的方法或响应式状态。
defineExpose 是什么?
defineExpose 是一个编译时宏(仅在 <script setup></script> 中可用),用于**主动声明子组件向父组件暴露的属性和方法**。它替代了 Vue 2 中的 vm.$emit 或 provide/inject 等间接方式,让父子通信更直接、类型更友好。
注意:它不是函数调用,而是顶层宏,不能写在条件语句或函数内部,必须在 <script setup></script> 的顶层直接使用。
如何正确暴露方法?
只需在子组件中定义好方法(如 const handleClick = () => {...}),然后在 defineExpose 中以对象形式列出要暴露的键名即可。Vue 会自动处理响应性与类型推导。
- 暴露普通函数:
defineExpose({ handleClick }) - 暴露带参数的方法:
defineExpose({ focusInput, resetForm })(无需额外包装) - 暴露响应式数据(如 ref):
defineExpose({ count, isActive }),父组件拿到的是解包后的值(非 ref 包装) - 暴露计算属性(需用
computed包裹):defineExpose({ fullName: computed(() => firstName.value + ' ' + lastName.value) })
父组件怎么调用?
父组件需用 ref 绑定子组件实例,再通过 .value 访问暴露的内容(因为 ref 持有组件实例)。
- 模板中:
<childcomponent ref="childRef"></childcomponent> - 脚本中:
const childRef = ref(null),然后在onMounted或事件回调里调用:childRef.value?.handleClick() - TS 用户注意:建议配合
defineExpose的返回类型做泛型标注(如const childRef = ref<instancetype childcomponent> | null>(null)</instancetype>),但更推荐用defineEmits+defineProps配合expose的自动类型推导
常见误区与注意事项
不暴露 = 父组件完全访问不到;暴露了但没赋值 = 对应字段为 undefined;暴露了 ref 类型数据 = 父组件拿到的是原始值(响应式已保留)。
- ❌ 错误:在
if块里写defineExpose({...})→ 编译报错 - ❌ 错误:暴露未定义的变量,如
defineExpose({ doSomething })但没声明doSomething→ 运行时报错 - ✅ 正确:所有暴露项都应在
defineExpose前声明,并保持命名一致 - ⚠️ 注意:暴露大量内部状态可能破坏封装性,优先考虑用
emit触发事件,仅对必要控制逻辑(如聚焦、重置、滚动到底部)使用defineExpose









