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

完整文档参考

相关推荐
子兮曰3 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A3 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
honkun63 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端