在Vue3的组件化开发中,父子组件间的通信是核心功能之一。本文将详细介绍五种父组件访问子组件属性/方法的实现方案,包含最新的
import { ref, onMounted } from 'vue'
const childRef = ref(null)
onMounted(() => {
console.log(childRef.value.childData) // 输出:子组件数据
childRef.value.childMethod() // 触发子组件方法
})
关键点说明:
子组件必须通过defineExpose显式暴露属性/方法父组件通过ref.value 访问时需注意生命周期时序支持TS类型推导(需配合TypeScript使用)7
二、getCurrentInstance(备用方案)
适用于需要访问组件上下文的高级场景:
// 子组件
defineExpose({ customMethod: () => {} })
// 父组件
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
const childComponent = instance.refs.childRef
childComponent.customMethod()
注意事项:
属于底层API,建议优先使用ref方案需要严格保证组件渲染顺序在SSR环境中可能出现问题7
三、事件驱动模式(props + emit)
符合单向数据流原则的通信方式:
defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const updateData = (val) => {
emit('update:modelValue', val)
}
适用场景:
需要维持数据单向流动表单组件等需要双向绑定的情况9
四、依赖注入模式(provide/inject)
解决深层嵌套组件访问问题:
// 祖先组件
provide('sharedData', ref('可响应数据'))
// 后代组件
const data = inject('sharedData')
优势:
跨多层组件直接访问配合响应式API实现状态共享3
五、状态管理方案(Pinia/Vuex)
全局状态管理场景下的访问方式:
// store/userStore.js
export const useUserStore = defineStore('user', {
state: () => ({ userInfo: null })
})
// 任意组件
const store = useUserStore()
store.userInfo = '全局数据'
适用场景:
需要跨多组件共享状态复杂应用的状态管理3
注意事项与最佳实践
单向数据流原则:优先考虑props/emit方式传递数据封装性保护:子组件应明确暴露的最小API集合生命周期时序:确保在onMounted之后访问refTypeScript支持:使用interface定义暴露类型15
方案对比表
方法适用层级响应式维护成本适用场景ref + defineExpose父子✔️低精准方法调用provide/inject跨级✔️中深层组件共享事件驱动父子✔️低数据变更通知状态管理全局✔️高复杂应用状态共享