子组件访问父组件的数据
1. 通过props传递
父组件通过属性传递数据,子组件通过 defineProps 接收
<!-- 父组件 -->
<Child :title="parentTitle" />
<!-- 子组件 -->
<script setup>
const props = defineProps(['title'])
console.log(props.title) // 访问父组件数据
</script>
2. $attrs / useAttrs()
用于透传非 props 的属性和事件(如 class、style、@click 等)。当子组件未声明 props 时,父组件传递的所有属性会自动注入到 $attrs
<!-- 父组件 -->
<Child @custom-event="handleEvent" data-type="external" />
<!-- 子组件 -->
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
// 透传属性到内部元素
<div v-bind="attrs">...</div>
</script>
3. slot标签访问插槽内容
父组件通过插槽向子组件传递 DOM 内容。子组件通过 <slot> 标签控制渲染位置
<!-- 父组件 -->
<Child>
<template #header> <!-- 具名插槽 -->
<h1>{{ parentData }}</h1>
</template>
</Child>
<!-- 子组件 -->
<div>
<slot name="header" /> <!-- 插槽内容渲染位置 -->
</div>
父组件访问子组件的数据
1. 自定义事件传递子组件数据(defineEmits)
子组件通过 defineEmits 声明事件,使用 emit() 触发事件并携带数据
<!-- 子组件 -->
<script setup>
const emit = defineEmits(['update-data'])
emit('update-data', { value: 42 }) // 触发事件,传递子组件数据
</script>
<!-- 父组件 -->
<Child @update-data="(payload) => parentData = payload.value" />
2. ref + defineExpose
父组件通过 ref 获取子组件实例,子组件使用 defineExpose 显式暴露数据/方法
<!-- 父组件 -->
<Child ref="child" />
<script setup>
const childRef = useTemplateRef('child')
childRef.value?.childMethod() // 调用子组件方法
</script>
<!-- 子组件 -->
<script setup>
const childData = ref(0)
defineExpose({
childData,
childMethod: () => { ... }
})
</script>
3. 作用域插槽 scoped slots
子组件通过 <slot> 暴露数据给插槽内容,父组件在 <template> 中使用 v-slot 接收数据。典型场景: 封装可复用的数据驱动型组件(如表单、列表),父组件控制渲染逻辑。
<!-- 子组件 -->
<slot :item="internalData" /> <!-- 暴露 item 属性 -->
<!-- 父组件 -->
<Child>
<template v-slot="slotProps">
{{ slotProps.item }} <!-- 访问子组件数据 -->
</template>
</Child>
组件的双向通信
1. v-model + defineModel
v-model本质是:modelValue+@update:modelValue的语法糖defineModel()宏自动处理双向绑定
<!-- 父组件 -->
<Child v-model="parentValue" />
<!-- 子组件 -->
<script setup>
const model = defineModel() // 自动绑定
model.value = "new" // 修改触发父组件更新
</script>
2. 依赖注入(provide/inject)
父组件用 provide 共享数据,子孙组件用 inject 获取
<!-- 父组件 Provider.vue -->
<script setup>
import { ref, provide, readonly } from 'vue'
// 1. 创建响应式数据
const sharedData = ref('初始数据')
// 2. 创建修改方法(确保单向数据流)
const updateData = (newValue) => {
sharedData.value = newValue
}
// 3. 提供只读数据和修改方法
provide('sharedData', readonly(sharedData)) // 只读响应式数据
provide('updateSharedData', updateData) // 修改方法
</script>
总结
props、$attrs、插槽slot用于子访问父;
emit、ref + expose、作用域插槽用于父访问子;
v-model、provide/inject 实现双向或跨层通信,灵活组合应对不同场景。