子组件访问父组件的数据
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
实现双向或跨层通信,灵活组合应对不同场景。