1. 父组件给子组件传值 (Props):子用父值
基本用法
父组件 (ParentComponent.vue):
vue
<template>
<ChildComponent :title="childTitle" :count="childCount" />
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const childTitle = ref('子组件标题')
const childCount = ref(10)
</script>
子组件 (ChildComponent.vue):
vue
<template>
<div>
<h2>{{ title }}</h2>
<p>Count: {{ count }}</p>
</div>
</template>
<script setup>
// 定义 props
const props = defineProps({
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
})
</script>
文档参考
2. 父组件调用子组件的方法 (Expose & Ref):父用子方法
父组件 (ParentComponent.vue):
vue
<template>
<ChildComponent ref="childRef" />
<button @click="callChildMethod">调用子组件方法</button>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const childRef = ref(null)
function callChildMethod() {
if (childRef.value) {
childRef.value.increment() //直接调用子组件中的increment的方法
}
}
</script>
子组件 (ChildComponent.vue):
vue
<template>
<div>子组件计数: {{ count }}</div>
</template>
<script setup>
import { ref } from 'vue'
const count = ref(0)
// 暴露给父组件的方法
function increment() {
count.value++
}
// 如果子组件中用const XX 来定义方法,就需要 使用 defineExpose 暴露方法,父组件才能用到
defineExpose({
increment
})
</script>
文档参考
3. 子组件改变父组件中的值 (Emit Events):子改父值
父组件 (ParentComponent.vue):
vue
<template>
<div>父组件计数: {{ parentCount }}</div>
<ChildComponent @update-count="updateCount" />
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const parentCount = ref(0)
function updateCount(newValue) {
parentCount.value = newValue
}
</script>
子组件 (ChildComponent.vue):
vue
<template>
<button @click="handleClick">更新父组件计数</button>
</template>
<script setup>
// 定义 emits
const emit = defineEmits(['updateCount'])
function handleClick() {
// 触发事件并传递新值
emit('updateCount', 5)
}
</script>
使用 v-model 实现双向绑定:父传子&子传父
父组件 (ParentComponent.vue):
vue
<template>
<ChildComponent v-model="count" />
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const count = ref(0)
</script>
子组件 (ChildComponent.vue):
vue
<template>
<button @click="updateValue">增加: {{ modelValue }}</button>
</template>
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
function updateValue() {
emit('update:modelValue', props.modelValue + 1)
}
</script>
文档参考
4. 子组件调用父组件的方法 (Emit Events): 子用父方法
父组件 (ParentComponent.vue):
vue
<template>
<ChildComponent @call-parent="parentMethod" />
</template>
<script setup>
import ChildComponent from './ChildComponent.vue'
function parentMethod(message) {
console.log('父组件方法被调用:', message)
}
</script>
子组件 (ChildComponent.vue):
vue
<template>
<button @click="callParent">调用父组件方法</button>
</template>
<script setup>
const emit = defineEmits(['callParent'])
function callParent() {
emit('callParent', '来自子组件的消息')
}
</script>
5. 其他通信方式
依赖注入 (Provide/Inject)
适合跨多层组件通信
祖先组件 (AncestorComponent.vue):
vue
<template>
<ParentComponent />
</template>
<script setup>
import { provide, ref } from 'vue'
import ParentComponent from './ParentComponent.vue'
const sharedData = ref('共享数据')
provide('sharedKey', sharedData)
</script>
后代组件 (DescendantComponent.vue):
vue
<script setup>
import { inject } from 'vue'
const sharedData = inject('sharedKey')
</script>
文档参考
总结对比表
通信方式 | 方向 | 适用场景 | 优点 | 缺点 |
---|---|---|---|---|
Props | 父 → 子 | 传递初始数据 | 明确的数据流,易于理解 | 单向数据流 |
Emit Events | 子 → 父 | 子组件通知父组件 | 明确的事件流 | 需要父组件监听 |
Refs & Expose | 父 → 子 | 访问子组件方法/属性 | 直接访问 | 破坏封装性 |
v-model | 双向 | 表单输入等双向绑定 | 语法糖,简洁 | 仅适用于特定场景 |
Provide/Inject | 任意 | 跨多层组件 | 避免逐层传递 | 数据来源不明确 |
最佳实践建议
- 优先使用 props 和 emits:保持数据流的清晰和可预测性
- 谨慎使用 refs:这会破坏组件的封装性
- 复杂场景使用状态管理:如 Pinia 适用于全局或复杂状态
- 考虑组件设计:如果通信过于复杂,可能需要重新思考组件结构