Vue3 expose() 函数(保姆级教程)

Vue3 expose() 函数

Vue 3 中的 expose() 函数是 Composition API 提供的一个重要工具,用于在组件中控制哪些方法或属性可以被父组件访问。它是用来替代 Vue 2 中 this.$emitthis.$expose 等方式的一种更现代、更清晰的写法。

核心概念

在 Vue 3 的组件中,使用 <script setup> 语法时,组件对外暴露的 API 默认是不包括内部定义的函数或变量的。如果父组件需要调用子组件的方法或访问子组件的属性,就需要通过 expose() 明确声明暴露的内容。

一句话总结:expose() 函数允许你在 Vue 3 的组件中显式暴露方法或属性,供父组件使用。

基础语法

在使用 <script setup> 的组件中,直接调用 expose() 函数即可:

import { defineExpose } from 'vue'

const privateMethod = () => {
    console.log('这是私有方法,不会被父组件访问')
}

const publicMethod = () => {
    console.log('这是暴露给父组件的方法')
}

// 暴露 publicMethod 方法
defineExpose({
    publicMethod
})

默认不暴露

如果不使用 expose(),组件中定义的函数和变量默认不会被暴露。例如:

const greet = () => {
    console.log('你好,Vue 3')
}

父组件中通过 ref 获取该组件实例时,是无法调用 greet() 方法的。

用法一:暴露单个方法

import { defineExpose } from 'vue'

const sayHello = () => {
    console.log('Hello from child component')
}

defineExpose({
    sayHello
})

用法二:暴露多个属性和方法

import { defineExpose, ref } from 'vue'

const count = ref(0)
const increment = () => {
    count.value++
}

defineExpose({
    count,
    increment
})

此时父组件可以通过 ref 调用 increment(),并读取 count 的值。

进阶特性

expose() 在 Vue 3 的 <script setup> 模式中非常关键,它提供了灵活控制组件 API 的能力。以下是一些常见的高级用法:

特性 说明 示例
选择性暴露 你可以选择暴露部分函数或属性,避免暴露不必要的内容 defineExpose({ sayHello })
暴露响应式数据 可以暴露 ref、reactive 等响应式对象,父组件能响应变化 defineExpose({ counter: count })
暴露计算属性 通过 expose 暴露 computed 属性,父组件可以访问并响应 const age = computed(() => 2024 - birthYear.value); defineExpose({ age })
暴露自定义事件 父组件可以通过 ref.value.$emit() 调用子组件的事件 defineExpose({ triggerEvent })

示例:暴露计算属性

import { defineExpose, ref, computed } from 'vue'

const birthYear = ref(2000)
const age = computed(() => 2024 - birthYear.value) // 计算当前年龄

// 暴露 age 属性
defineExpose({
    age
})

父组件通过 ref 可以访问 childComponent.age.value,并响应其变化。

实战应用

场景一:父组件调用子组件方法

假设子组件有一个 reset() 方法,需要在父组件中调用。

子组件(ChildComponent.vue)

<script setup>
import { defineExpose } from 'vue'

const reset = () => {
    console.log('子组件的 reset 方法被调用')
}

defineExpose({
    reset
})
</script>

父组件(ParentComponent.vue)

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

const childRef = ref()

const callChildReset = () => {
    childRef.value.reset() // 调用子组件暴露的方法
}
</script>

<template>
  <ChildComponent ref="childRef" />
  <button @click="callChildReset">重置子组件</button>
</template>

场景二:暴露响应式数据供父组件读取

子组件

<script setup>
import { defineExpose, ref } from 'vue'

const counter = ref(0)

const increment = () => {
    counter.value++
}

defineExpose({
    counter
})
</script>

<template>
  <p>当前计数:{{ counter }}</p>
  <button @click="increment">+1</button>
</template>

父组件

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

const childRef = ref()

const showCounter = () => {
    console.log('子组件计数器值:', childRef.value.counter.value)
}
</script>

<template>
  <ChildComponent ref="childRef" />
  <button @click="showCounter">显示子组件计数器</button>
</template>

注意事项

  • expose() 只在 <script setup> 语法中使用,不能与 setup() 函数混用
  • 暴露的 API 不能是函数表达式,必须是命名函数或变量引用
  • 不要暴露过多内部实现细节,暴露的 API 应保持简洁
  • 不能暴露 props,因为 props 是只读的,且 Vue 会自动处理它们

总结

expose() 函数是 Vue 3 中用于控制组件对外 API 的关键工具,它让父组件能够访问子组件的特定方法和属性,是 <script setup> 语法下实现组件间通信的推荐方式。掌握它的使用,能提升组件的可维护性和封装性。