标准答案
- script setup 组件默认是封闭的,父组件通过 ref 不能直接访问子组件内部所有变量。
- defineExpose 可以显式暴露方法或属性,例如 validate、reset、focus。
- 暴露内容应该少而稳定,优先暴露命令式动作,不要把内部响应式状态、临时变量和实现细节全暴露出去。
- 父组件拿到组件 ref 后,要考虑组件是否已经挂载、是否可能为 null。
- 如果需求是普通数据传递或状态同步,优先用 props / emits / v-model;只有确实需要命令式调用时再用 defineExpose。
题目解析
defineExpose 的核心是封装边界。它不是让父组件绕过子组件接口随便操作内部实现。
组件库常用它暴露 validate、clearValidate、scrollToField、focus 这类能力。
暴露太多内部状态会让父子耦合变强,后续重构子组件时容易破坏外部调用方。
代码示例
表单输入组件可以只暴露 focus 和 reset,而不是暴露所有内部状态。
Vue
<!-- NameInput.vue -->
<script setup lang="ts">
import { ref } from 'vue'
const value = defineModel<string>({ required: true })
const inputRef = ref<HTMLInputElement | null>(null)
function focus() {
inputRef.value?.focus()
}
function reset() {
value.value = ''
}
defineExpose({
focus,
reset
})
</script>
<template>
<input ref="inputRef" v-model="value">
</template>常见误区
- 把组件内部所有 ref 都 defineExpose 出去,父组件直接依赖内部实现。
- 用 defineExpose 代替 emits,让子组件状态变化变成父组件命令式修改。
- 父组件没有处理组件 ref 为空的情况。