Vue3中的常见组件通信之$attrs

Vue3中的常见组件通信之$attrs

概述

​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。

组件关系 传递方式
父传子 1. props 2. v-model 3. $refs 4. 默认插槽、具名插槽
子传父 1. props 2. 自定义事件 3. v-model 4. $parent 5. 作用域插槽
祖传孙、孙传祖 1. $attrs 2. provide、inject
兄弟间、任意组件间 1. mitt 2. pinia

props和自定义事件详见:
Vue3中的常见组件通信之props和自定义事件

mitt用法详见:
Vue3中的常见组件通信之mitt

v-model用法详见:

Vue3中的常见组件通信之v-model

接下是$attrs的用法。

5.$attrs

$attrs用于当前组件的父组件与当前组件的子组件相互通信,也就是祖孙间通信。

5.1准备三个组件

首先准备三个组件,Father组件代码如下:

vue 复制代码
<template>
  <div class="father">
    <h3>父组件</h3>
		<Child/>
  </div>
</template>

<script setup lang="ts" name="Father">
	import Child from './Child.vue'	
	
</script>

<style scoped>
	.father{
		background-color: rgb(74, 108, 110);
		padding: 20px;
		color: #fff;
	}
</style>

Child组件代码如下:

vue 复制代码
<template>
	<div class="child">
		<h3>子组件</h3>
		<GrandChild/>
	</div>
</template>

<script setup lang="ts" name="Child">
	import GrandChild from './GrandChild.vue'
</script>

<style scoped>
	.child{
		margin-top: 20px;
		background-color: rgb(213, 217, 219);
		padding: 20px;
		color: #000;
	}
</style>

GrandChild组件代码如下:

vue 复制代码
<template>
	<div class="grand-child">
		<h3>孙组件</h3>		
	</div>
</template>

<script setup lang="ts" name="GrandChild">
	
</script>

<style scoped>
	.grand-child{
		margin-top: 20px;
		background-color: rgb(164, 85, 31);
		padding: 20px;
		color: #fff;		
	}
</style>

运行后效果如下:

5.2祖传孙的实现

首先给父组件添加一些数据:

typescript 复制代码
	import {ref} from 'vue'
	//数据
	let a = ref(100)
	let b = ref(200)
	let c = ref(300)

然后在父组件页面上呈现出来:

vue 复制代码
<ul>
    <li>a: {{ a }}</li>
    <li>b: {{ b }}</li>
    <li>c: {{ c }}</li>
</ul>

同时将数据传给Child组件:

vue 复制代码
<Child :a="a" :b="b" :c="c"/>

接下来再写Child组件的代码,首先要接收数据:

typescript 复制代码
//接收props
defineProps(['a'])

页面呈现出来如下:

vue 复制代码
<ul>
    <li>a: {{ a }}</li>
</ul>

呈现效果如下:

注意父组件给子组件传递了abc三个数据,但是子组件只接收了一个数据a,那么剩下的两个bc数据去哪里了呢?此时需要借助浏览器的vue开发者工具,打开后可以看到b和c的数据在attrs里。

在页面呈现一下attrs:

vue 复制代码
<ul>
    <li>a: {{ a }}</li>
    <li>其他: {{ $attrs }}</li>
</ul>

页面效果如下:

可以看出来$attrs是个对象格式的数据,这样Child组件就可以把attrs的数据传递给GrandChild组件:

vue 复制代码
<!-- 将attrs传给GrandChild -->
<GrandChild :="$attrs"/>

**注意:**上面的代码等价于下面的代码:

vue 复制代码
<GrandChild v-bind="$attrs"/>

由于$attrs的值是对象{''b'':200,"c":300},所以上的代码又等价于:

vue 复制代码
<GrandChild :b="b" :c="c"/>

然后在GrandChild组件中接收b和c:

typescript 复制代码
defineProps(['b','c'])

并在页面呈现:

vue 复制代码
<ul>    
    <li>b: {{ b }}</li>
    <li>c: {{ c }}</li>
</ul>

运行结果如下:

这样就实现了祖传孙的过程,在上面的代码中,Child组件也可以不接收任何props,Father组件传的所有的数据都通过$attrs传给GrandChild组件,运行效果如下:

5.3孙传祖的实现

如果实现孙传祖的效果,需要在Father组件中给Child传递一个函数,GrandChild组件接收后触发这个函数,与props实现子传父的做法一致,如下是在Father组件中定义函数如下:

typescript 复制代码
function changeA(value:number){
    a.value += value
}

传给Child组件:

html 复制代码
<Child :a="a" :b="b" :c="c" :changeA="changeA"/>

在GrandChild组件中接收:

typescript 复制代码
defineProps(['a','b','c','changeA'])

再添加一个按钮,绑定定click事件,触发函数,并传递参数:

html 复制代码
<button @click="changeA(100)">点我更改父组件中a的值增加100</button>

这样就实现了孙传祖的过程,当点击按钮时,Father组件中的a值会增加100,每点击一次增加100,这个新的值也会再传给GrandChild,实现的效果就是点击按钮后Father组件和GrandChild组件中的a值会同时变化,如下图所示:

以下是各个组件的完整代码:

Father组件:

vue 复制代码
<template>
  <div class="father">
    <h3>父组件</h3>
	<ul>
		<li>a: {{ a }}</li>
		<li>b: {{ b }}</li>
		<li>c: {{ c }}</li>
	</ul>
	<Child :a="a" :b="b" :c="c" :changeA="changeA"/>
  </div>
</template>

<script setup lang="ts" name="Father">
	import Child from './Child.vue'	
	import {ref} from 'vue'

	//数据
	let a = ref(100)
	let b = ref(200)
	let c = ref(300)

	function changeA(value:number){
		a.value += value
	}

</script>

<style scoped>
	.father{
		background-color: rgb(74, 108, 110);
		padding: 20px;
		color: #fff;
	}
</style>

Child组件:

vue 复制代码
<template>
	<div class="child">
		<h3>子组件</h3>
		<!-- <ul>
			<li>a: {{ a }}</li>
			<li>其他: {{ $attrs }}</li>
		</ul> -->
		<!-- 将attrs传给GrandChild -->
		<GrandChild :="$attrs"/>
	</div>
</template>

<script setup lang="ts" name="Child">
	import GrandChild from './GrandChild.vue'
	//接收props
	// defineProps(['a'])
</script>

<style scoped>
	.child{
		margin-top: 20px;
		background-color: rgb(213, 217, 219);
		padding: 20px;
		color: #000;
	}
</style>

GrandChild组件

vue 复制代码
<template>
	<div class="grand-child">
		<h3>孙组件</h3>		
		<ul>
			<li>a: {{ a }}</li>
			<li>b: {{ b }}</li>
			<li>c: {{ c }}</li>
		</ul>
		<button @click="changeA(100)">点我更改父组件中a的值增加100</button>
	</div>
</template>

<script setup lang="ts" name="GrandChild">

//接收props
defineProps(['a','b','c','changeA'])
	
</script>

<style scoped>
	.grand-child{
		margin-top: 20px;
		background-color: rgb(164, 85, 31);
		padding: 20px;
		color: #fff;		
	}
	button{
		color: #000;
	}
</style>

5.4小结

$attrs用于祖孙间的通信,$attrs是一个对象,包含所有父组件传入的标签属性。

相关推荐
于指尖飞舞6 分钟前
在vue3中使用datav完整引入时卡在加载页面的解决方法
vue3·报错·datav
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
CodeClimb5 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
沈梦研5 小时前
【Vscode】Vscode不能执行vue脚本的原因及解决方法
ide·vue.js·vscode
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb6 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角6 小时前
CSS 颜色
前端·css
轻口味6 小时前
Vue.js 组件之间的通信模式
vue.js
九酒6 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔7 小时前
HTML5 新表单属性详解
前端·html·html5