theme: qklhk-chocolate
highlight: srcery
本文正在参加「金石计划 . 瓜分6万现金大奖」
最近笔者在做大屏项目的时候,由于组件数据传递,一层传递一层,使用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>
<PassVal
placeholder="我是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);
以结果如下:
感谢观看,大佬不喜勿喷,感谢~!也感谢我家莎老板
的鼓励,因为一个人的,我想要变得更好。
暂无评论内容