VUE之组件(父子与非父子通信)

本文详细介绍了Vue组件间的通信方式,包括父子组件通过props和自定义事件进行通信,跨级组件的逐层传递,以及兄弟组件借助事件总线bus进行通信。还探讨了非父子组件通信的Vuex解决方案和常见组件通信的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

组件组织

通常一个应用会以一棵嵌套的组件树的形式来组织。
在这里插入图片描述
日常开发里,我们可以按照功能将一个网页拆分成很多个部分,每个部分就是一个组件。
例如,可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的子组件。
在这里插入图片描述

父子组件通信

父子组件传值通信
假设第二层组件想和第一层组件进行通信,分析其传值过程
1、(第一层向第二层传值):父组件通过props传值到子组件,如此便实现父子组件向下通信
2、(第二层向第一层传值):子组件通过触发自定义事件向父组件传值,如此便实现了父子组件向上通信
在这里插入图片描述

跨级组件通信

跨级组件传值通信
假设第三层组件想和第一层组件进行通信
1、(第一层组件向第三层组件传值)—禁止第一层直接传值到第三层,需要逐层传递,即1→2→3,此时便可以实现跨级组件向下通信
2、(第三层组件向第一层组件传值)—通过触发自定义事件将数据传递至第二层,然后第二层通过事件触发传递至第一层,如此逐层传递,便可以实现跨级组件向上通信
在这里插入图片描述

兄弟组件通信

兄弟组件传值通信
假设第三层组件想和同层的另一个组件进行通信。
如果还是逐层传递至第二层,再由第二层传递至第三层,此时代码量十分累赘复杂,这也不符合Vue的定义(Vue是一个轻量级的视图层框架)。
在这里插入图片描述

兄弟|非父子组件通信

引用官方文档:
因为基于组件树结构的事件流方式让人难以理解,并且在组件结构扩展的过程中会变得越来越脆弱。这种事件方式确实不太好,我们也不希望在以后让开发者们太痛苦。
官方推荐的状态管理方案是 Vuex。不过如果项目不是很大,状态管理也没有很复杂的话,使用 Vuex 有种杀鸡用牛刀的感觉,当然,这也是要根据自己的需求来的。
本节介绍下另一种方法,即bus/总线/发布订阅模式/观察者模式来解决
文档术语:
通过使用事件中心,允许组件自由交流,这个集中式的事件中间件就是 Bus总线。

语法:
在组件中使用$emit, $on, $off 分别来分发、监听、取消监听事件

接下来依次做下介绍
首先定义两个兄弟组件,如下所示

<div id="demo">
			<my-btn :count="6"></my-btn>
			<my-btn :count="2"></my-btn>
		</div>
		<script type="text/javascript">
			Vue.component('my-btn',{
				props:{
					count:Number
				},
				template:`<button>按钮{{count}}</button>`
			})
			new Vue({
				el:'#demo'
			})
		</script>

在这里插入图片描述

要求:点击一个组件,另一个兄弟组件也发生改动,两者数值相等

兄弟|非父子组件通信

兄弟组件通信
接下来结合案例,介绍下如何通过bus/总线/发布订阅模式/观察者模式来解决非父子组件通信。

第一步(注册全局bus总线):
创建一个Vue实例,将其赋值给Vue.prototype.bus
在这里插入图片描述

解析:在Vue的prototype类上挂载了一个bus属性,该属性指向Vue实例。只要在其后通过Vue实例创建组件,则每个组件都会有bus属性
第一步(注册全局bus):
写法2:Vue bus的使用(兄弟|非父子组件传值)–>可以使用一个空的Vue实例作为中央事件总线new Vue(),此外也可以写成$bus
在这里插入图片描述

有人可能会问“为什么加$,作用是什么”?

接下来简单介绍下$作用

$命名法则

简介:
$ 是在 Vue 所有实例中都可用的属性的一个简单约定。这样做会避免和已被定义的数据、方法、计算属性产生冲突,即避免命名冲突。接下来结合案例测试下

<div id="demo"></div>
		<script type="text/javascript">
			Vue.prototype.action='吃'
			new Vue({
				el:'#demo',
				mounted(){
					document.write(this)
					document.write(this.action)
				}
			})
		</script>

在这里插入图片描述
在这里插入图片描述![

接下来,在data数据里声明个同名的变量,如下所示

<div id="demo"></div>
		 <script type="text/javascript">
			Vue.prototype.action = '吃' ;
		 	    	new Vue({
		 	    		el:'#demo',
		 				data:{
		 					action:'睡'
		 				},
		 				mounted(){
		 					document.write(this)
		 					document.write(this.action)
		 				}
		 	    	})	
			
		</script>

在这里插入图片描述
修改代码如下所示
将Vue挂载实例命名前,加上前缀$,用于避免和已被定义的数据、方法、计算属性产生冲突,即避免命名冲突。

<div id="demo"></div>
			<script type="text/javascript">
				Vue.prototype.$action = '吃' ;
				new Vue({
					el:'#demo',
					data:{
						action:'睡'
					},
					created(){
						document.write(this)
						document.write(this.$action)
						document.write(this.action)
					}
				})
			</script>

在这里插入图片描述

兄弟|非父子组件通信

接下来继续介绍兄弟组件通信
再来梳理下需求,即当点击某个组件改变时,希望同时触发另外一个非父级组件改动,所以接下来需要在子组件绑定事件

<div id="app">
				<my-btn :count="6"></my-btn>
				<my-btn :count="2"></my-btn>
			</div>
			<script type="text/javascript">
				Vue.prototype.$bus=new Vue();
				Vue.component('my-btn',{
					props:{
						count:Number
					},
					template:`<button @click="handelClick">按钮{{count}}</button>`,
					methods:{
						handelClick(){
							alert(this.count)
						}
					}
				})
				new Vue({
					el:'#app'
				})
			</script>

在这里插入图片描述

兄弟|非父子组件通信

第二步:通过中央事件线程 b u s , 分 发 事 件 属 性 bus,分发事件属性 busemit

在这里插入图片描述

解析:
this. b u s 为 中 央 事 件 总 线 程 n e w V u e 实 例 , 通 过 bus为中央事件总线程new Vue实例,通过 bus线newVueemit来分发事件,分发事件时可以携带参数option。
子组件分发完毕后,其他组件需要进行监听接收分发的事件,此时可以借助生命周期钩子来实现。
第三步:
结合生命周期钩子监听和接收分发的事件,监听事件属性 o n 。 ! [ 在 这 里 插 入 图 片 描 述 ] ( h t t p s : / / i m g − b l o g . c s d n i m g . c n / 20191030165453801. p n g ) ! [ 在 这 里 插 入 图 片 描 述 ] ( h t t p s : / / i m g − b l o g . c s d n i m g . c n / 2019103016551267. p n g ? x − o s s − p r o c e s s = i m a g e / w a t e r m a r k , t y p e Z m F u Z 3 p o Z W 5 n a G V p d G k , s h a d o w 1 0 , t e x t a H R 0 c H M 6 L y 9 i b G 9 n L m N z Z G 4 u b m V 0 L 3 d l a X h p b l 80 N T Y y N j E 2 N g = = , s i z e 1 6 , c o l o r F F F F F F , t 7 0 ) 第 三 步 : 结 合 生 命 周 期 钩 子 监 听 和 接 收 分 发 的 事 件 , 监 听 事 件 属 性 on。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20191030165453801.png) ![在这里插入图片描述](https://img-blog.csdnimg.cn/2019103016551267.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTYyNjE2Ng==,size_16,color_FFFFFF,t_70) 第三步: 结合生命周期钩子监听和接收分发的事件,监听事件属性 on![](https://imgblog.csdnimg.cn/20191030165453801.png)![](https://imgblog.csdnimg.cn/2019103016551267.png?xossprocess=image/watermark,typeZmFuZ3poZW5naGVpdGk,shadow10,textaHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NTYyNjE2Ng==,size16,colorFFFFFF,t70)on。
接下来修改数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第三步:
结合生命周期钩子监听和接收分发的事件,监听事件属性$on。
解决方案之前说过,利用子组件data,拷贝份父组件传递数据,后续即可维护自身数据,而不改动父组件数据

Vue.component('my-btn',{
					data(){
						return {
							childCount:this.count
						}
					},
					props:{
						count:Number
					},
					template:`<button @click="handelClick">按钮{{childCount}}</button>`,
					methods:{
						handelClick(){
							this.$bus.$emit('change',this.childCount+1);
						}
					},
					mounted() {
						var _this = this;
						_this.$bus.$on('change',function(Option){
							document.write(Option);
						_this.childCount = Option
					
					})
					}
				})
				

第四步:取消|清除监听事件,取消监听属性$off
日常开发里,为了避免不要的BUG,建议在使用bus时,加上清除监听操作,代码如下
在这里插入图片描述
如果需要监听多个组件,只需要更改 bus 的 eventName
在这里插入图片描述
步骤小结:
1、注册全局$bus
使用空Vue实例作为中央事件总线new Vue(),注册全局$bus总线
2、分发$emit
通过中央事件线程$bus,A组件,分发事件属性$emit
3、监听$on
结合生命周期钩子,B组件监听和接收分发的事件,监听事件属性$on
4、取消$off
取消|清除监听事件,取消监听属性$off

父子组件通信小结

引用官网的一句话:
父子组件的关系可以总结为 prop 向下传递,事件向上传递
父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息,如下图所示:
在这里插入图片描述

非父子组件通信小结

如果需要子对子传参,可以先从传到父组件,再传到子组件,但这样写过于累赘。

方案:
为了便于开发,vue 推出了一个状态管理工具 vuex,可以很方便实现组件之间的参数传递,后期结合工程化介绍。
官方推荐的状态管理方案是 Vuex。不过如果项目不是很大,状态管理也没有很复杂的话,使用 Vuex 有种杀鸡用牛刀的感觉。所以本节介绍下另一种方法,即bus/总线/发布订阅模式/观察者模式来解决

跨级组件通信

跨级通信方案
使用 a t t r s 和 attrs和 attrslisteners实现祖孙组件之间的数据传递,也就是多重嵌套组件之间的数据传递

版本注意:
本方法针对vue2.4版本及以上,使用 a t t r s 和 attrs和 attrslisteners来实现的
首先看下跨级组件通信自上而下步骤,案例如下
在这里插入图片描述
祖父级
在这里插入图片描述
父级
在这里插入图片描述
孙子级
在这里插入图片描述
祖父级调用
跨级组件通信
跨级组件通信自上而下
祖父级:用于动态数据的绑定与事件的定义
父级:通过设置v-bind=" a t t r s " 和 v − o n = " attrs" 和v-on=" attrs"von="listeners"来充当中间人
孙子级:通过 a t t r s 和 attrs和 attrslisteners来获取数据和事件

一般来说,自上而下的通信会涉及到props与$attrs,而自下而上的通信,都是通过事件触发,然后层层上传。
跨级组件通信自下而上
方案一:
$emit逐层上传
在这里插入图片描述
孙子级
在这里插入图片描述
父级
在这里插入图片描述
祖父级
在这里插入图片描述

跨级组件通信自下而上
方案二:通过$listeners接收事件

在这里插入图片描述
孙子级
在这里插入图片描述
父级
在这里插入图片描述
祖父级

常见组件通信BUG

(1)bus. o n 监 听 多 次 绑 定 , 造 成 事 件 多 次 触 发 问 题 描 述 : 只 要 页 面 没 有 强 制 刷 新 , 存 在 组 件 切 换 , b u s . on监听多次绑定,造成事件多次触发 问题描述:只要页面没有强制刷新,存在组件切换,bus. onbus.on方法会被多次绑定,造成事件多次触发
方案:注册的总线事件(Bus)要在组件销毁时(beforeDestroy/destroyed)卸载,否则会多次挂载,造成触发一次但多个响应的情况

在这里插入图片描述

方案2:在每次调用方法前先解绑事件bus. o f f , 然 后 在 重 新 绑 定 b u s . off ,然后在重新绑定bus. offbus.on ,该做法不常用,简单了解即可。

课堂总结

(1)数值传递大概可以分为两种,即父子传值与非父子传值
(2)非父子传值包含:跨级传值、兄弟传值
(3)父向子传递:props
(4)子向父传递: e m i t ( 5 ) 兄 弟 之 间 传 递 : 借 助 中 间 代 理 , 即 中 央 事 件 总 线 emit (5)兄弟之间传递:借助中间代理,即中央事件总线 emit5线bus
使用$emit, $on, $off 分别来分发、监听、取消监听事件
(6)跨级通信:
a t t r s 可 以 获 取 父 作 用 域 传 入 的 值 ( 不 包 括 p r o p s 中 的 ) , attrs可以获取父作用域传入的值(不包括props中的), attrspropslisteners相当于父作用域的事件监听器,那我们就可以用这两个属性实现祖孙之间的数据通信

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值