Vue 3 父子&爷孙组件通信

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 任意 跨多层组件 避免逐层传递 数据来源不明确

最佳实践建议

  1. 优先使用 props 和 emits:保持数据流的清晰和可预测性
  2. 谨慎使用 refs:这会破坏组件的封装性
  3. 复杂场景使用状态管理:如 Pinia 适用于全局或复杂状态
  4. 考虑组件设计:如果通信过于复杂,可能需要重新思考组件结构

完整文档参考

相关推荐
袁煦丞31 分钟前
2025.8.18实验室【代码跑酷指南】Jupyter Notebook程序员的魔法本:cpolar内网穿透实验室第622个成功挑战
前端·程序员·远程工作
Joker Zxc35 分钟前
【前端基础】flex布局中使用`justify-content`后,最后一行的布局问题
前端·css
无奈何杨38 分钟前
风控系统事件分析中心,关联关系、排行、时间分布
前端·后端
Moment44 分钟前
nginx 如何配置防止慢速攻击 🤔🤔🤔
前端·后端·nginx
晓得迷路了1 小时前
栗子前端技术周刊第 94 期 - React Native 0.81、jQuery 4.0.0 RC1、Bun v1.2.20...
前端·javascript·react.js
前端小巷子1 小时前
Vue 自定义指令
前端·vue.js·面试
玲小珑1 小时前
Next.js 教程系列(二十七)React Server Components (RSC) 与未来趋势
前端·next.js
Mike_jia1 小时前
UptimeRobot API状态监控:零成本打造企业级业务健康看板
前端
江城开朗的豌豆1 小时前
React状态更新踩坑记:我是这样优雅修改参数的
前端·javascript·react.js