最近笔者在做大屏项目的时候,由于组件数据传递,一层传递一层,使用vuex或者pinia又显得过于笨重。故而想起了那个传说中的v-bind="$attrs"以及v-on="$listeners",下面就来聊下使用:
上图组件之间的关系如下:
ComponentGrandParent为最外层父级组件(爷)*ComponentParent为中间层父级组件(父)*ComponentChild为子组件ComponentGrandParent组件想把props传递给ComponentChild就通常需要在ComponentParent中通过属性一个个的传递
//ComponentParent组件
<template><ComponentChild :propa="prop1":propb="prop2":propc="prop3".../>
</template>
如果需要传递的属性多,而且ComponentParent中没有用到的ComponentGrandParent传递过来的属性的时候,就很尴尬,很不优雅,有时候还需要在写watch监听传递过来的数据,然后再赋值给data中的prop1,然后再传递给ComponentChild
使用$attrs能解决上述问题,那么什么是$attrs呢?
透传 Attributes 是指由父组件传入,且没有被子组件声明为props或是组件自定义事件的 attributes 和事件处理函数。默认情况下,若是单一根节点组件,$attrs 中的所有属性都是直接自动继承自组件的根元素。
大白话讲就是没有父组件传递过来的props,在子组件中没有对应的props声明,那么在子组件中就可以通过v-on:$attrs将父组件的props透传给孙组件,在二次封装一些elementui的组件有奇效
纸上得来终觉浅,下面来看下实际的使用,目录结构如下:
src├─ blocks│ └─ PassVal│ ├─ components│ │ └─ PassInput.vue│ └─ PassVal.vue├─ view│ ├─ basic│ │ └─ BasicView.vue├─ App.vue└─ main.js
BasicView.vue(父组件)中引入PassVal.vue(子组件);PassVal.vue(子组件)中引入PassInput.vue(孙组件)
//BasicView.vue代码如下:
<template><div class="basic"><h3><i class="title_icon"></i>基础知识</h3><PassValplaceholder="我是placerholder":clearable="true":defaultVal="defaultVal"@changGrandChildVal="changGrandChildVal"/></div>
</template>
<script> import PassVal from "@/blocks/PassVal/PassVal.vue";
export default {data() {return {defaultVal: "测试透传",};},components: {PassVal,},methods: {/** * @function input值修改回调函数 */changGrandChildVal(val) {console.log("PassInput组件的值变了", val);},},
}; </script>
<style scoped> .basic {width: 100%;height: 100%;
} </style>
- 在
PassVal想要传递三个属性placeholder="我是placerholder"、:clearable="true"以及:defaultVal="defaultVal"
接着来看下在PassVal中的处理:
//PassVal.vue
<template><div class="passval"><el-divider content-position="left">1-$attr和 $listeners</el-divider><div class="container"><div class="flex-two"><passInput v-bind="$attrs" v-on="$listeners"></passInput></div></div></div>
</template>
<script> import PassInput from "./components/PassInput.vue";
export default {components: {PassInput,},props: {defaultVal: {type: String,default: "输入框默认值",},},
}; </script>
<style scoped> .passval {width: 100%;height: 100%;
} </style>
- 这里通过
v-bind="$attrs"和v-on="$listeners"将属性和方法透传下去 - 如果在
PassVal.vue中有关于来自父组件BasicView.vue相关的props声明,那么v-bind="$attrs"透传的属性会将声明的这个属性剔除,透传余下的porps属性。* 例如:如果在PassVal.vue中的props中声明defaultVal,那么父组件BasicView.vue传递过来的defaultVal将无法通过v-bind="$attrs"透传给子组件PassInput.vue
而在PassInput.vue组件中
<template><div class="pass-input"><el-input v-bind="$attrs" v-model="value" @input="inputHandler"></el-input></div>
</template>
<script> export default {name: "PassInput",created() {console.log("我是$attrs", this.$attrs);console.log("我是$listeners", this.$listeners);},data() {return {value: "",};},methods: {/** * @function el-input的输入回调函数 */inputHandler(val) {this.$emit("changGrandChildVal", val);},},
}; </script>
<style scoped> .pass-input {width: 100%;height: 100%;
} </style>
从而实现了优雅的属性透传,在组件封装中比较有用。
生命周期中的console.log("我是$attrs", this.$attrs)和console.log("我是$listeners", this.$listeners);以结果如下:
感谢观看,大佬不喜勿喷,感谢~!也感谢我家莎老板的鼓励,因为一个人的,我想要变得更好。
最后
为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

![[从零开始]用python制作识图翻译器·四](https://img-blog.csdnimg.cn/df8992b1bde444ef89e8f7ba83722f63.png)

















![【SpringBoot高级篇】SpringBoot集成RocketMQ消息队列]](https://img-blog.csdnimg.cn/fea2a79aafb5459880a838e38d727ac9.png)