当前位置: 首页 > news >正文

Vue3+Vite 08:父子组件通信

一、前置准备:创建并引入子组件

在 Vue 中,引入并使用一个组件分为两步:创建子组件文件 → 父组件引入后直接使用。<script setup>语法下,组件引入后自动注册,无需额外配置。

操作步骤

  1. 在项目src/components文件夹下,新建Child.vue文件(子组件)
  2. 在父组件src/App.vue中引入子组件,直接在模板中使用
子组件src/components/Child.vue
<template> <div class="child-box"> <p>我是子组件</p> </div> </template> <script setup> </script> <style scoped> .child-box { border: 1px solid #42b983; padding: 20px; margin: 20px 0; } </style>
父组件src/App.vue
<template> <div style="padding: 20px;"> <h3>我是父组件</h3> <!-- 直接使用子组件标签 --> <Child /> </div> </template> <script setup> // 引入子组件 import Child from './components/Child.vue' </script>

运行后即可看到父子组件的层级关系,后续所有通信示例都基于这个基础结构修改。

二、父传子:defineProps

1. 作用

父组件向子组件传递数据,是最常用的通信方式。子组件通过defineProps声明要接收的数据,父组件通过属性绑定传值。

2. 基础写法

简单场景下,用数组声明要接收的属性名。

子组件代码
<template> <div class="child-box"> <p>子组件接收的标题:{{ title }}</p> <p>子组件接收的数量:{{ num }}</p> </div> </template> <script setup> // 声明要接收的属性 const props = defineProps(['title', 'num']) // 脚本中访问props数据:props.title </script>
父组件代码
<template> <div style="padding: 20px;"> <h3>父组件</h3> <!-- 静态传值:直接写字符串 --> <Child title="静态标题" num="100" /> <!-- 动态传值:用v-bind绑定响应式数据 --> <Child :title="parentTitle" :num="parentNum" /> </div> </template> <script setup> import { ref } from 'vue' import Child from './components/Child.vue' const parentTitle = ref('动态标题') const parentNum = ref(200) </script>

3. 进阶写法

项目中推荐使用对象写法,支持类型校验、默认值、必填设置

<script setup> const props = defineProps({ // 基础类型校验 title: String, // 多类型支持 num: [Number, String], // 必填 + 类型校验 username: { type: String, required: true }, // 带默认值 status: { type: Boolean, default: false } }) </script>

注意:

props只读的,子组件中绝对不能直接修改,否则控制台会报错。如果需要修改,必须通过子传父的方式通知父组件修改。

三、子传父:defineEmits

1. 作用

子组件向父组件发送消息、传递数据。子组件通过defineEmits声明要触发的事件,调用emit触发事件;父组件通过v-on监听事件并接收数据。

2. 代码

子组件代码
<template> <div class="child-box"> <p>子组件</p> <button @click="sendToParent">给父组件发消息</button> </div> </template> <script setup> // 声明要触发的事件 const emit = defineEmits(['sendMsg']) const sendToParent = () => { // 触发事件,第二个参数开始是要传递的数据 emit('sendMsg', '我是子组件传来的数据') } </script>
父组件代码
<template> <div style="padding: 20px;"> <h3>父组件,接收数据:{{ receiveMsg }}</h3> <!-- 监听子组件的sendMsg事件 --> <Child @sendMsg="handleReceive" /> </div> </template> <script setup> import { ref } from 'vue' import Child from './components/Child.vue' const receiveMsg = ref('') // 事件处理函数,参数就是子组件传来的数据 const handleReceive = (data) => { receiveMsg.value = data } </script>

3. 关键说明

  • defineEmits接收数组,里面是所有要触发的事件名
  • 触发事件格式:emit('事件名', 参数1, 参数2...)
  • 事件名推荐使用短横线命名(如send-msg),和原生事件规范保持一致

四、父调用子组件能力:defineExpose

1. 作用

父组件通过ref获取子组件实例,直接调用子组件的方法、访问子组件的数据。适合需要主动触发子组件行为的场景(比如打开子组件弹窗、调用子组件重置方法)。

2. 代码

子组件代码
<template> <div class="child-box"> <p>子组件计数:{{ count }}</p> </div> </template> <script setup> import { ref } from 'vue' const count = ref(0) const addCount = () => { count.value++ } // 主动暴露给父组件的内容,未暴露的内容父组件无法访问 defineExpose({ count, addCount }) </script>
父组件代码
<template> <div style="padding: 20px;"> <h3>父组件</h3> <button @click="callChild">调用子组件方法</button> <!-- 给子组件绑定ref --> <Child ref="childRef" /> </div> </template> <script setup> import { ref, onMounted } from 'vue' import Child from './components/Child.vue' // 创建ref,和模板上的ref属性名一致 const childRef = ref(null) const callChild = () => { // 通过.value访问子组件暴露的内容 childRef.value.addCount() console.log('子组件数据:', childRef.value.count) } onMounted(() => { // 必须在挂载完成后才能获取到子组件实例 console.log('挂载完成,子组件实例:', childRef.value) }) </script>

3. 注意

  • 子组件必须用defineExpose主动暴露内容,父组件才能访问,这是 Vue3 的安全限制
  • 父组件中ref变量在setup同步执行时是null,必须在onMounted及之后的阶段才能访问到实例

五、总结

  1. 父传子:子组件用defineProps声明属性,父组件通过属性绑定传值,单向只读
  2. 子传父:子组件用defineEmits声明事件并触发,父组件用@事件名监听接收
  3. 父调子:子组件用defineExpose暴露能力,父组件通过ref获取实例调用
http://www.jsqmd.com/news/1101635/

相关文章:

  • 3步搞定安卓应用安装:Windows平台APK安装器完全指南
  • SRWE:如何用Windows运行时窗口编辑器彻底改变你的多分辨率工作流?
  • 2026年必学!收藏这份AI大模型应用指南,小白也能轻松掌握数字助理的奥秘
  • AI 电动吸奶器智能功率 MOSFET 完整选型方案
  • 告别轮询!用C#和Fleck库5分钟搞定一个WebSocket聊天服务端
  • 计算机毕业设计之基于离线数仓的化妆品推荐系统
  • 3步搞定电子课本下载:tchMaterial-parser让教育资源获取效率提升10倍
  • 如何免费获取百度网盘高速下载链接?Python直链解析工具完整指南
  • Bamtone HCT耐电流测试方案:AI时代,如何确保PCB线路不“掉链子“?
  • 2026年GEO优化工具权威评测
  • wvp-GB28181-pro深度解析:国标视频监控平台架构设计与实现方案
  • 告别手算!用Python SymPy库5分钟搞定Smith标准型和Jordan标准型
  • 5步体验REPENTOGON:以撒的结合终极脚本扩展器深度体验指南
  • 从Claude Code迁移到Kimi Code:AI编程助手进阶玩法与工作流重构指南
  • 数据中心服务器视窗粘接怎么选?两类3M方案满足不同应用需求
  • 收藏!小白程序员必看:从AI工具使用到认知闭环的AI转型指南
  • 基于MVVM架构的FlaUInspect:现代化UI自动化元素检查的高效稳定解决方案
  • 告别虚拟机:基于逍遥模拟器与Burp Suite的PC端移动应用抓包实战指南
  • 5分钟快速上手:OpenVINO AI音频插件让Audacity拥有超能力 [特殊字符]
  • 3个智能功能让《鸣潮》体验升级:专业工具箱助你轻松优化画质与账号管理
  • 3大核心功能:tchMaterial-parser电子课本高效下载终极方案
  • AI生成单元测试到底靠不靠谱?实测12个主流工具后,我发现了这4个致命短板
  • 智慧医院APP开发方案:互联网医院系统源码架构、功能与部署全解析
  • 【AI编程未来趋势权威预测】:2024-2030年5大不可逆技术拐点与开发者生存指南
  • 【MySQL】内置函数
  • WVP-GB28181-Pro视频点播超时故障终极解决方案:从根源诊断到系统化根治
  • 一套后端API驱动四端——织码在线教育系统多端统一学习体验设计
  • GitHub Copilot Review vs DeepCode vs SonarQube AI(2024企业级对比白皮书)
  • Claude Code性能瓶颈诊断工具箱:CPU占用飙升、延迟突增、token泄漏——3分钟定位根因(含实时监控脚本)
  • 别再手动数氢键了!用Materials Studio脚本一键搞定周期性体系统计(附完整Perl代码)