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
是一个对象,包含所有父组件传入的标签属性。