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. 考虑组件设计:如果通信过于复杂,可能需要重新思考组件结构

完整文档参考

相关推荐
zwjapple5 分钟前
docker-compose一键部署全栈项目。springboot后端,react前端
前端·spring boot·docker
像风一样自由20202 小时前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
aiprtem3 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊3 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术3 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
幽络源小助理3 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
GISer_Jing3 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止4 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall4 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴4 小时前
简单入门Python装饰器
前端·python