标准答案

  1. script setup 组件默认是封闭的,父组件通过 ref 不能直接访问子组件内部所有变量。
  2. defineExpose 可以显式暴露方法或属性,例如 validate、reset、focus。
  3. 暴露内容应该少而稳定,优先暴露命令式动作,不要把内部响应式状态、临时变量和实现细节全暴露出去。
  4. 父组件拿到组件 ref 后,要考虑组件是否已经挂载、是否可能为 null。
  5. 如果需求是普通数据传递或状态同步,优先用 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 为空的情况。

作者信息