Vue 系列之:组件通讯
子组件调用父组件方法
1、直接在子组件中通过 this.$parent.event 来调用父组件的方法
父组件:
<template><p><child></child></p>
</template>
<script>import child from './child';export default {components: {child},methods: {fatherMethod() {console.log('测试');}}};
</script>
子组件:
<template><p><button @click="childMethod()">点击</button></p>
</template>
<script>export default {methods: {childMethod() {this.$parent.fatherMethod();}}};
</script>
2、父组件使用 v-on 监听事件,子组件使用 $emit 件触发事件
@ 是 v-on 的缩写
父组件:
<template><p><child @method1="fatherMethod"></child></p>
</template>
<script>import child from './child';export default {components: {child},methods: {fatherMethod(params) {console.log('测试', params);}}};
</script>
子组件:
<template><p><button @click="childMethod()">点击</button></p>
</template>
<script>export default {methods: {childMethod() {this.$emit('method1', params); // params 为参数,可不传 // this.$emit('method1');}}};
</script>
3、父组使用 v-bind 绑定事件,子组件用 props 接收事件
: 是 v-bind 的缩写
父组件:
<template><p><child :method1="fatherMethod"></child></p>
</template>
<script>import child from './child';export default {components: {child},methods: {fatherMethod() {console.log('测试');}}};
</script>
子组件:
<template><p><button @click="childMethod()">点击</button></p>
</template>
<script>export default {props: {method1: {type: Function,default: null}},methods: {childMethod() {if (this.method1) {this.method1();}}}};
</script>
父组件调用子组件方法
1、通过 ref 直接调用子组件的方法
父组件:
<template><div><Button @click="fatherMethod">点击调用子组件方法</Button><Child ref="child"/></div>
</template> <script>
import Child from './child';
export default {methods: {fatherMethod() {this.$refs.child.childMethod();},},
}
</script>
子组件:
<template><div>我是子组件</div>
</template><script>
export default {methods: {childMethod() {console.log('我是子组件的方法');},},
};</script>
2、通过组件的$emit、$on方法(可以,但是没必要)
父组件:
<template><div><Button @click="fatherMethod">点击调用子组件方法</Button><Child ref="child"/></div>
</template> <script>
import Child from './child';
export default {methods: {fatherMethod() {this.$refs.child.$emit("getChildMethod") //子组件$on中的名字},},
}
</script>
子组件:
<template><div>我是子组件</div>
</template><script>
export default {mounted() {this.$nextTick(function() {this.$on('getChildMethod', this.childMethod);});},methods: {childMethod() {console.log('我是子组件方法');}}
};
</script>
兄弟组件
-
方法1:通过父组件作为中转
-
通过 ref 和 $parent
-
通过 provide 和 inject
-
-
方法2:使用 EventBus 事件总线
-
方法3:vuex,下一篇内容会讲
EventBus 使用方式
1、初始化——全局定义
可以将 eventBus 绑定到 vue 实例的原型上,也可以直接绑定到 window 对象上
//main.js//注册方式一
Vue.prototype.$EventBus = new Vue();//注册方式二
window.EventBus = new Vue();
2、监听事件
//使用方式一
this.$EventBus.$on('eventName', (param1, param2, ...) => {//需要执行的代码
})//使用方式二
EventBus.$on('eventName', (param1, param2, ...) => {//需要执行的代码
})
3、触发事件
//使用方式一
this.$EventBus.$emit('eventName', param1, param2,...)//使用方式二
EventBus.$emit('eventName', param1, param2,...)
4、移除监听事件
为了避免在监听时,事件被反复触发,通常需要在页面销毁时移除事件监听。或者在开发过程中,由于热更新,事件可能会被多次绑定监听,这时也需要移除事件监听。
//使用方式一
this.$EventBus.$off('eventName');//使用方式二
EventBus.$off('eventName');//移除所有
EventBus.$off();
5、示例
简单示例一:
<!--组件 A.vue-->
<script>
export default { mounted() { // 监听事件this.$EventBus.$on('custom-event', this.handleEvent) }, methods: { handleEvent(data) { console.log(data) } }
}
</script><!--组件 B.vue-->
<template> <button @click="handleClick">触发事件</button>
</template> <script>
export default {data() {return {str: '我来自 B 组件'}}methods: {handleClick() {// 触发事件this.$EventBus.$emit('custom-event', this.str) } }
}
</script>
示例二:
假设兄弟组件有三个,分别是 A、B、C 组件,A 组件如何获取 B 或者 C 组件的数据
这时候就可以使用 EventBus。EventBus 是一种发布/订阅模式,用于在组件之间传递事件和数据。A 组件可以监听由 B 或 C 组件发布的事件,并在事件处理函数中获取传递的数据。
思路:
A 组件中使用 Event.$on 监听事件
B、C 组件中使用 Event.$emit 触发事件
// A.vue
<template> <div>A 接收到的数据: {{ receivedData }}</div>
</template> <script> export default { data() { return { receivedData: null }; }, mounted() { // 监听事件 EventBus.$on('custom-event', (data) => { this.receivedData = data.message; }); }, beforeDestroy() { // 组件销毁前,移除事件监听器 EventBus.$off('custom-event'); }
};
</script>
// B.vue 和 C.vue
<template> <button @click="sendData">发送数据</button>
</template> <script>
export default { methods: {sendData() { const data = { message: 'I am from B' };// 触发事件EventBus.$emit('data-from-a', data); } }
};
</script>
多层组件(爷孙)
provide() 和 inject[]
用于将数据或方法暴露给组件树中的任何后代组件,哪怕是深层次的后代组件都可以访问到这些数据,而无需通过 props 层层传递。
注意:provide 和 inject 主要用于单向数据传递,即从祖先组件流向后代组件。虽然可以在后代组件中修改注入的数据,但这种做法会破坏单向数据流的原则,导致数据流向不清晰,难以调试,因此不建议这样做。
Vue2 用法:
<!--爷/父 组件-->
<template><div id="app"><Children></Children></div>
</template><script>
import Children from "./Children.vue";
export default {name: 'parent',components: { Children },provide() {return {parentEvent: this.myEvent,parentData: this.message,parentStr: '字符串数据'};},data() {return {message: 'data中的数据'}},methods: {myEvent(params1, params2) {console.log(params1, params2)},}
};
</script>
<!--子/孙 组件-->
<template><el-button @click="handleClick">测试</el-button>
</template><script>
export default {name: 'child',inject: ["parentEvent", "parentData", "parentStr"],methods: {handleClick() {this.parentEvent('参数1', '参数2');console.log(this.parentData)console.log(this.parentStr)}}
};
</script>
从上到下依次打印:
参数1 参数2
data中的数据
字符串数据
Vue3 用法:
<!--爷/父 组件-->
<template><div id="app"><Children></Children></div>
</template><script setup>
import { ref, provide } from "vue";
import Children from "./Children.vue";
const message = ref('data中的数据');
const str = '字符串数据'
function myEvent(params1, params2) {console.log(params1, params2)
}
provide('parentEvent', myEvent);
provide('parentData', message);
provide('parentStr', str);
</script>
<!--子/孙 组件-->
<template><el-button @click="handleClick">测试</el-button>
</template><script setup>
import { inject } from "vue";
const parentEvent = inject('parentEvent');
const parentData = inject('parentData');
const parentStr = inject('parentStr', '默认值');function handleClick() {parentEvent('参数1', '参数2')console.log(parentData.value)console.log(parentStr)
}
</script>
细心的朋友已经发现:在 Vue3 中,子组件打印的是 parentData.value,这说明 parentData 是一个响应式对象。
直接总结:
| 特性 | Vue2 | Vue3 |
|---|---|---|
| 响应式支持 | provide 提供的数据不是响应式的 | provide 提供的数据是响应式的 |
| 默认值支持 | 不支持默认值 | 支持默认值,inject 的第二个参数就是默认值 |
$attrs 和 $listeners
$attrs
$attrs 是一个对象,包含了父组件传递给子组件的所有非 prop 属性(即没有在 props 中定义的属性)。
当你希望将父组件传递的属性传递给子组件的子组件时,可以使用 $attrs。
父组件:
<!-- 父组件 -->
<template><div id="app"><Children :params1="params1" :params2="params2" /></div>
</template><script>
import Children from "./Children.vue";
export default {name: 'parent',components: { Children },data() {return {params1: '测试1',params2: '测试2',params3: '测试3',}},mounted() {setTimeout(() => {this.params2 += 'timeout'}, 5000);},
};
</script>
子组件:
<!-- 子组件 -->
<template><div><p>params1: {{ $attrs.params1 }}</p><p>params2: {{ $attrs.params2 }}</p><p>params3: {{ $attrs.params3 }}</p><Groundson v-bind="$attrs" :params4="params4"/></div>
</template><script>
import Groundson from "./Groundson.vue";
export default {name: 'children',components: { Groundson },props: {params1: {type: String,default: ""}},data() {return {params4: '测试4'}},mounted() {console.log("children $attrs:", this.$attrs);},
};
</script>
孙组件:
<!-- 孙组件 -->
<template><div></div>
</template>
<script>export default {name: 'groundson',mounted() {console.log("groundson $attrs:", this.$attrs);},
};
</script>
页面:

打印:

总结:
-
没有通过 v-bind 传递给子组件的,子组件的 $attrs 中不会有该属性
-
通过 v-bind 传递给了子组件,但是子组件使用了 props 接收的,子组件的 $attrs 中不会有该属性
-
$attrs 中的属性值是响应式的
-
在子组件中使用 v-bind=“$attrs” 可以将子组件的 $attrs 中的所有属性都传递给孙子组件,孙子组件也是按同样的规则接收
inheritAttrs 的作用:
观察页面元素发现:

子组件的根元素和孙子组件的根元素都多了一些属性
官方解释:默认情况下,父组件传递的,但没有被子组件解析为 props 的 attributes 绑定会被“透传”。这意味着当我们有一个单根节点的子组件时,这些绑定会被作为一个常规的 HTML attribute 应用在子组件的根节点元素上。我们可以通过设置 inheritAttrs 为 false 来禁用这个默认行为。
例如在子组件中加上 inheritAttrs: false:

子组件根节点的属性消失了,由于没有在孙子组件中设置,孙子组件的根节点还保留着属性
$listeners
$listeners 包含了父组件传递给子组件的所有事件监听器(即 v-on 绑定的事件)。
与 $attrs 类似, $attrs 是传递属性, $listeners 是传递方法。这里就不再举例了。
注意:在 Vue3 中,$listeners 已经被移除,其功能被合并到了 $attrs 中。
相关文章:
Vue 系列之:组件通讯
子组件调用父组件方法 1、直接在子组件中通过 this.$parent.event 来调用父组件的方法 父组件: <template><p><child></child></p> </template> <script>import child from ./child;export default {components: {chi…...
【Linux实践系列】:用c语言实现一个shell外壳程序
🔥本文专栏:Linux Linux实践项目 🌸博主主页:努力努力再努力wz 那么今天我们就要进入Linux的实践环节,那么我们之前学习了进程控制相关的几个知识点,比如进程的终止以及进程的等待和进程的替换,…...
STL map 的 lower_bound(x)、upper_bound(x) 等常用函数
【STL map 简介】 ● STL map 是一种关联容器,存储键值对,每个键(key value)是唯一的,而值(mapped value)可以重复。构建 STL map 时,无论元素插入顺序如何,STL map 中的…...
【A2DP】SBC 编解码器互操作性要求详解
目录 一、SBC编解码器互操作性概述 二、编解码器特定信息元素(Codec Specific Information Elements) 2.1 采样频率(Sampling Frequency) 2.2 声道模式(Channel Mode) 2.3 块长度(Block Length) 2.4 子带数量(Subbands) 2.5 分配方法(Allocation Method) 2…...
Computational Linguistics期刊全解析:领域顶刊的投稿指南与学术价值
在人工智能与语言学交叉融合的浪潮中,《Computational Linguistics》(CL)作为该领域的标杆期刊,始终是研究者发表前沿成果的首选平台。本文将从期刊影响力、投稿策略、收稿方向等角度,为学者提供一份全面的指南。 一、…...
【量化科普】Sharpe Ratio,夏普比率
【量化科普】Sharpe Ratio,夏普比率 🚀量化软件开通 🚀量化实战教程 在量化投资领域,夏普比率(Sharpe Ratio)是一个非常重要的风险调整后收益指标。它由诺贝尔经济学奖得主威廉F夏普(William…...
运行OpenManus项目(使用Conda)
部署本项目需要具备一定的基础:Linux基础、需要安装好Anaconda/Miniforge(Python可以不装好,直接新建虚拟环境的时候装好即可),如果不装Anaconda或者Miniforge,只装过Python,需要确保Python是3.…...
TikTok Shop欧洲市场爆发,欧洲TikTok 运营网络专线成运营关键
TikTok在欧洲的影响力还在持续攀升,日前,TikTok发布了最新的欧盟执行和使用数据报告,报告中提到: 2024年7~12月期间,TikTok在欧盟地区的月活用户达1.591亿,较上一报告期(2024年10月发布…...
基于YOLO11深度学习的电瓶车进电梯检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】
《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...
计算机毕业设计SpringBoot+Vue.js制造装备物联及生产管理ERP系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
微服务保护:Sentinel
home | Sentinelhttps://sentinelguard.io/zh-cn/ 微服务保护的方案有很多,比如: 请求限流 线程隔离 服务熔断 服务故障最重要原因,就是并发太高!解决了这个问题,就能避免大部分故障。当然,接口的并发…...
labelimg标注的xml标签转换为yolo格式标签
本文不生产技术,只做技术的搬运工!!! 前言 在yolo训练时,我们需要对图像进行标注,而使用labelimg标注时如果直接选择输出yolo格式的数据集,则原始数据的很多信息无法被保存,因此一版…...
VUE3开发-9、axios前后端跨域问题解决方案
VUE前端解决跨域问题 前端页面需要改写 如果无效,记得重启服务器 后端c#解决跨域问题 前端js取值,后端c#跨域_c# js跨域-CSDN博客...
机试准备第12天
首先学习队列,队列有先进先出的特性。广度优先遍历需要基于队列实现,C中的stl引入了队列的实现方式。队列支持push(),进入队尾,pop()出队,队头出队,front()获取队首元素,back()获取队尾元素&…...
计算机二级MS之PPT
声明:跟着大猫和小黑学习随便记下一些笔记供大家参考,二级考试之前将持续更新,希望大家二级都能轻轻松松过啦,过了二级的大神也可以在评论区留言给点建议,感谢大家!! 文章目录 考题难点1cm25px…...
伊藤积分(Ito Integral):随机世界中的积分魔法
伊藤积分(Ito Integral):随机世界中的积分魔法 在研究随机微分方程(SDE)和布朗运动时,伊藤积分(Ito Integral)是一个绕不开的关键概念。它是处理布朗运动随机项 ( d W ( t ) dW(t)…...
【Deepseek应用】Zotero+Deepseek 阅读和分析文献(下)
【Deepseek应用】Deepseek R1 本地部署(OllamaDockerOpenWebUI) 【Deepseek应用】ZoteroDeepseek 阅读和分析文献(上) 【Deepseek应用】ZoteroDeepseek 阅读和分析文献(下) 使用邀请码 cXfb9wOT 注册 硅基流…...
人工智能与深度学习的应用案例:从技术原理到实践创新
第一章 引言 人工智能(AI)作为21世纪最具变革性的技术之一,正通过深度学习(Deep Learning)等核心技术推动各行业的智能化进程。从计算机视觉到自然语言处理,从医疗诊断到工业制造,深度学习通过模拟人脑神经网络的层次化学习机制,实现了对复杂数据的高效分析与决策。本…...
Docker和DockerCompose基础教程及安装教程
Docker的应用场景 Web 应用的自动化打包和发布。自动化测试和持续集成、发布。在服务型环境中部署和调整数据库或其他的后台应用。从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。 CentOS Docker 安装 使用官方安装脚本自动安装 安装命令…...
ArcGIS操作:13 生成最小外接矩阵
应用情景:筛选出屋面是否能放下12*60m的长方形,作为起降场候选点(一个不规则的形状内,判断是否能放下指定长宽的长方形) 1、面积初步筛选 Area ≥ 720 ㎡ 面积计算见 2、打开 ArcToolbox → Data Management Tools …...
从轨迹到网络:广州休闲步行空间格局刻画 | 论文全解析与方法论深度拆解
从轨迹到网络:广州休闲步行空间格局刻画 | 论文全解析与方法论拆解 原文:From trajectories to network: Delineating the spatial pattern of recreational walking in Guangzhou》 一、论文核心概览:摘要与关键词 1.1 核心摘要解析 本文的核心内容可拆解为5个核心模块,…...
终极指南:用Java打造你的专属微信机器人 - 深入解析wechat-api框架
终极指南:用Java打造你的专属微信机器人 - 深入解析wechat-api框架 【免费下载链接】wechat-api 🗯 wechat-api by java7. 项目地址: https://gitcode.com/gh_mirrors/we/wechat-api 想象一下这样的场景:每天早上7点,你的微…...
嵌入式正交编码器软件解码库设计与实现
1. QuadratureEncoder 库概述QuadratureEncoder 是一个专为嵌入式系统设计的正交编码器信号处理库,面向 STM32、ESP32、nRF52 等主流 MCU 平台,提供高精度、低开销、抗干扰的旋转位置与速度检测能力。该库不依赖特定硬件外设(如 STM32 的 TIM…...
RAG深度解析一:从参数化知识到检索增强的范式重构
【内容定位】深度技术原理【文章日期】2026-03-27【场景引入】进入2026年3月,一场围绕大语言模型“可信性”的讨论在技术社区再度升温。开发者们早已不再争论模型参数量,而是转向一个更实际的问题:如何让动辄千亿参数的大模型,在回…...
数据稠密计算的算法优化:从理论到实践
数据稠密计算的算法优化:从理论到实践 引言 作为一名在数据深渊里捞了十几年 Bug 的女码农,我见过太多因为算法选择不当导致的性能问题。在数据稠密计算中,算法的选择和优化是提升计算性能的关键因素之一。今天,我们来聊聊数据稠密…...
3步释放20GB空间:给Android用户的系统减负指南
3步释放20GB空间:给Android用户的系统减负指南 【免费下载链接】universal-android-debloater Cross-platform GUI written in Rust using ADB to debloat non-rooted android devices. Improve your privacy, the security and battery life of your device. 项目…...
别再死记硬背公式了!Cesium中Entity姿态(HPR)的获取与设置,一个例子讲透
Cesium中Entity姿态控制的本质:从HPR到四元数的思维跃迁 当你第一次在Cesium中加载一个3D模型,却发现它头朝下或者背对镜头时,那种挫败感我深有体会。传统教程往往直接扔给你一堆转换公式,却很少解释为什么需要这些看似复杂的数学…...
python-flask-djangol框架的高校毕业生就业信息实习管理系统
目录需求分析与功能规划技术选型与架构设计数据库模型设计功能模块实现数据统计与可视化测试与部署文档与维护项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作需求分析与功能规划 明确系统核心目标为管理高校毕业生就业和实习信…...
突破性解决方案:3步解决Calibre中文路径乱码,实现100%原生中文支持
突破性解决方案:3步解决Calibre中文路径乱码,实现100%原生中文支持 【免费下载链接】calibre-do-not-translate-my-path Switch my calibre library from ascii path to plain Unicode path. 将我的书库从拼音目录切换至非纯英文(中文&#x…...
告别单打独斗!Apipost 8协作版数据迁移保姆级教程(含团队项目处理)
Apipost 8协作版数据迁移实战:从个人到团队的无缝衔接 第一次打开Apipost 8协作版时,我盯着那个"迁入项目"按钮犹豫了整整十分钟——作为独立开发者,我的旧版本里积累了237个接口文档和56个测试集合,它们就像我精心搭建…...
