在 Vue 3 的 <script setup> 语法中,defineExpose 是一个特殊的编译宏,用于显式暴露组件内部的属性或方法,让父组件可以通过 ref 引用 访问到子组件的这些成员。

为什么需要 defineExpose

<script setup> 中,组件的内部状态(如变量、方法)默认是 私有 的,父组件无法直接通过 ref 访问。这是为了封装组件内部实现,避免外部随意修改。

如果父组件需要访问子组件的某些属性或方法,就必须通过 defineExpose 主动暴露。

基本用法

1. 子组件中使用 defineExpose 暴露成员

vue

<!-- 子组件 Child.vue -->
<script setup>
import { ref } from 'vue'

// 内部状态
const count = ref(0)
const name = ref('子组件')

// 内部方法
const increment = () => {
  count.value++
}

// 暴露给父组件的成员(对象形式)
defineExpose({
  count,    // 暴露响应式变量
  name,     // 暴露响应式变量
  increment // 暴露方法
})
</script>

<template>
  <div>子组件:count = {{ count }}</div>
</template>
2. 父组件通过 ref 访问子组件暴露的成员

vue

<!-- 父组件 Parent.vue -->
<script setup>
import { ref, onMounted } from 'vue'
import Child from './Child.vue'

// 创建 ref 引用子组件
const childRef = ref(null)

// 子组件挂载后才能访问(确保 ref 已指向子组件实例)
onMounted(() => {
  // 访问子组件暴露的属性
  console.log(childRef.value.name) // 输出:"子组件"
  console.log(childRef.value.count) // 输出:0

  // 调用子组件暴露的方法
  childRef.value.increment()
  console.log(childRef.value.count) // 输出:1
})
</script>

<template>
  <Child ref="childRef" />
</template>

注意事项

  1. 访问时机

    父组件必须在子组件 挂载完成后 才能通过 ref 访问暴露的成员(可在 onMounted 钩子中操作,或在模板中用可选链 ?. 避免初始化报错)。

    vue

    <!-- 模板中安全访问 -->
    <div>子组件count:{{ childRef?.count }}</div>
    
  2. 响应式保持

    如果暴露的是 refreactive 类型的响应式数据,父组件访问时仍能保持响应式(子组件修改后,父组件会自动更新)。

  3. 仅用于 <script setup>

    defineExpose<script setup> 特有的语法,普通的 <script> 组件(非 setup 语法)不需要它,直接通过 this 暴露即可。

  4. 暴露的是 “引用”

    父组件拿到的是子组件内部成员的引用,修改暴露的响应式数据会直接影响子组件(需谨慎操作,避免破坏组件封装性)。

总结

defineExpose 的核心作用是 打破 <script setup> 的默认私有性,让父组件能安全访问子组件的指定成员,适用于需要父子组件紧密交互的场景(如父组件调用子组件方法、获取子组件状态等)。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐