Vue 3 的父子组件传值主要遵循单向数据流的原则:父传子 和 子传父。

Vue 3 的父子组件传值主要遵循单向数据流 的原则:父传子子传父

以下是详细的实现方式、代码示例以及注意事项。

1. 父传子

父组件通过自定义属性 传递数据,子组件通过 defineProps 接收数据。

核心步骤:
  1. 父组件 :在子组件标签上绑定属性(如 :title="msg")。
  2. 子组件 :使用 defineProps 声明并接收属性。
代码示例:

父组件

html 复制代码
<template>
  <div>
    <h2>父组件</h2>
    <!-- 1. 传递静态值 -->
    <ChildComponent title="静态标题" />
    
    <!-- 2. 传递动态变量 -->
    <ChildComponent :title="parentMsg" :age="18" />
  </div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue'
import { ref } from 'vue'
const parentMsg = ref('来自父组件的动态消息')
</script>

子组件

html 复制代码
<template>
  <div class="child-box">
    <p>子组件接收到的标题:{{ title }}</p>
    <p>年龄:{{ age }}</p>
  </div>
</template>
<script setup>
// 2. 使用 defineProps 接收
// 写法一:数组写法(简单,但不直观)
// defineProps(['title', 'age'])
// 写法二:对象写法(推荐,可以限制类型和默认值)
const props = defineProps({
  title: {
    type: String,
    required: true, // 必填
    default: '默认标题' // 默认值
  },
  age: {
    type: Number,
    default: 0
  }
})
// 注意:在 JS 中使用 props 变量需要通过 props.title
console.log(props.title) 
</script>

⚠️ 注意

  • <template> 模板中直接使用变量名(如 title)。
  • <script> 代码中,需要通过 props.title 访问。
  • 不要在子组件中直接修改 props 传来的值 (如 props.title = 'new'),这会违反单向数据流,导致报错。

2. 子传父

父组件通过自定义事件 接收数据,子组件通过 defineEmits 触发事件并传参。

核心步骤:
  1. 父组件 :在子组件标签上监听事件(如 @change-msg="handleMsg")。
  2. 子组件 :使用 defineEmits 声明事件,并在合适时机调用 emit('事件名', 数据)
代码示例:

父组件

html 复制代码
<template>
  <div>
    <h2>父组件收到的消息:{{ msgFromChild }}</h2>
    
    <!-- 1. 绑定自定义事件 change-msg -->
    <ChildComponent @change-msg="handleChange" />
  </div>
</template>
<script setup>
import ChildComponent from './ChildComponent.vue'
import { ref } from 'vue'
const msgFromChild = ref('等待子组件发送...')
// 3. 定义处理函数,接收子组件传来的参数
const handleChange = (newMsg) => {
  msgFromChild.value = newMsg
}
</script>

子组件

html 复制代码
<template>
  <button @click="sendToParent">点击向父组件传值</button>
</template>
<script setup>
// 1. 声明要触发的事件
const emit = defineEmits(['change-msg'])
const sendToParent = () => {
  const message = '你好父组件,我是子组件'
  // 2. 触发事件并传递数据
  emit('change-msg', message)
}
</script>

💡 技巧

Vue 官方推荐事件命名使用 kebab-case (短横线命名) ,如 @update-value,因为在 HTML 模板中不区分大小写,@updateValue 可能会被解析成 @updatevalue


3. 双向绑定

如果你想要实现"父传子,子修改后自动传回父"的效果(类似 v-model),Vue 3 提供了更简便的方式。

方式一:使用 v-model (推荐)

Vue 3 的 v-model 默认绑定了 modelValue 属性和 update:modelValue 事件。
父组件

html 复制代码
<template>
  <!-- 等同于 :modelValue="text" @update:modelValue="text = $event" -->
  <ChildInput v-model="text" />
</template>

子组件

html 复制代码
<template>
  <!-- 必须绑定 value 并触发 input 事件 -->
  <input 
    type="text" 
    :value="modelValue" 
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>
方式二:defineModel 宏 (Vue 3.4+ 最新语法)

这是一个编译器宏,大大简化了双向绑定的代码。
子组件

html 复制代码
<script setup>
// 自动定义 props 和 emit,返回一个可写的 ref
const modelValue = defineModel()
// 修改 modelValue.value 会自动同步到父组件
</script>
<template>
  <input v-model="modelValue" />
</template>

4. 父组件直接操作子组件

如果父组件想要直接调用子组件的方法或访问其数据,可以通过 ref 获取子组件实例。
父组件

html 复制代码
<template>
  <ChildComponent ref="childRef" />
  <button @click="callChildMethod">调用子组件方法</button>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
// 1. 定义与 ref 同名的变量
const childRef = ref(null)
const callChildMethod = () => {
  // 3. 通过 value 访问子组件暴露的方法
  childRef.value.someMethod()
}
</script>

子组件

html 复制代码
<script setup>
const someMethod = () => {
  console.log('子组件方法被调用了!')
}
// 2. 必须使用 defineExpose 暴露方法或属性,父组件才能通过 ref 调用
defineExpose({
  someMethod
})
</script>

总结图表

传输方向 核心语法 父组件操作 子组件操作
父传子 Props <Child :msg="data" /> const props = defineProps(['msg'])
子传父 Emits <Child @update="fn" /> const emit = defineEmits(['update'])
双向绑定 v-model <Child v-model="data" /> defineProps + defineEmitsdefineModel
直接调用 Ref <Child ref="cRef" /> defineExpose({ method })
相关推荐
南风知我意9572 小时前
【重构思维】用位运算做权限管理
前端·面试·职场和发展·性能优化·重构
RPGMZ2 小时前
RPGMakerMZ 游戏引擎 野外采集点制作
javascript·游戏·游戏引擎·rpgmz·野外采集点
时寒的笔记2 小时前
js基础05_js类、原型对象、原型链&案例(解决无限debugger)
开发语言·javascript·原型模式
tryCbest2 小时前
Python之Flask开发框架(第五篇)- 使Flask + Vue 构建前后端分离项目教程
vue.js·python·flask
Free Tester2 小时前
手动访问网页用的chrome,和使用命令行指定端口启动的chrome,浏览器指纹是否一致
前端·chrome
2401_827499992 小时前
python核心语法05-模块
java·前端·python
ShineWinsu2 小时前
Chrome安全机制深度解析技术文章
前端·chrome·安全
EnoYao2 小时前
把你们开发扒个底朝天 Skill
前端·后端·程序员
程序员 沐阳2 小时前
从内容管控到硬件隔离:Chrome 安全防护体系深度拆解
前端·chrome·安全