咱们都知道 Vue 是采用组件化开发的模式,组件化的优点在于相对独立,易于维护,可复用。你能够把项目当作许多组件的组合而成。bash
既然项目中存在不少的组件,并且又是相对独立的,但组件间确定是存在数据的传递交互。Vue中给我提供比较多的方式去进行组件间的交互通讯。工具
这篇文章不打算详尽组件之间的通讯,而是说说利用 $attrs 与 $listeners 进行「嵌套组件」的通讯。组件化
能够想象一下项目中组件与组件的关系无外乎这么几种:父子,兄弟,祖孙(嵌套)。ui
一图胜千言this
经过上图,咱们能够了解常见的组件通讯方式。但实际的开发项目中可能并无这么简单,最近在作项目时遇到嵌套组件的状况,好比「组件A」包含「组件B」,「组件B」包含「组件C」。spa
那「组件A」与「组件C」如何通讯就是值得咱们商榷的问题,是利用 Vuex 仍是利用其余方式呢?code
首先 Vuex 是优秀的状态管理工具,对于复杂而又庞大的系统而言使用 Vuex 再好不过。component
但若是咱们的系统相对简单,而且「组件A」与「组件C」之间只是进行简单的数据传递,彷佛引入 Vuex 并非一个好的选择,相反会带来复杂度的上升。cdn
不过 Vue 在 2.4.0 版本添加了 2 个属性「$attrs」与「$listeners」,使用它们进行嵌套组件(祖孙)的通讯是一个不错的选择,接下来咱们就看看它们是什么,以及如何使用。对象
1.$attrs
官方解释:包含了父做用域中不做为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含全部父做用域的绑定 (class 和 style 除外),而且能够经过 v-bind="$attrs" 传入内部组件——在建立高级别的组件时很是有用。
2.$listeners
包含了父做用域中的 (不含 .native 修饰器的) v-on 事件监听器。它能够经过 v-on="$listeners" 传入内部组件——在建立更高层次的组件时很是有用。
简单来讲:$attrs 与 $listeners 是两个「对象」,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。
在不明白的话看个案例
//componentA
<template>
<div class="component-a">
<component-b :name="name" :tag="tag" :age="age" @click.native="say" @mouseover="sing"></component-b>
</div>
</template>
<script>
import componentB from "./ComponentB";
export default {
name: "componentA",
components: { componentB },
data() {
return {
name: "六哥",
tag: "帅",
age: 18
};
},
methods: {
say() {},
sing() {}
}
};
</script>
//componentB
<template>
<div class="component-b"></div>
</template>
<script>
export default {
name: "ComponentB",
props: {
age: Number
},
mounted() {
console.log(this.$attrs, this.$listeners);
//{name: "六哥", tag: "帅"}, {mouseover: ƒ}
}
};
</script>
复制代码
明白这两个属性以后,咱们来看看如何利用它进行祝祖孙组件之间的传递。假若有三个组件分别是「组件A」包含「组件B」,「组件B」包含「组件C」。
在上面案例的基础上,咱们添加「组件C」,并对「组件B」进行改善。
//componentB
<template>
<div class="component-b">
<component-c v-bind="$attrs" v-on="$listeners"></component-c>
</div>
</template>
<script>
import ComponentC from "./ComponentC";
export default {
name: "ComponentB",
components: { ComponentC }
};
</script>
//componentC
<template>
<div class="component-c"></div>
</template>
<script>
export default {
name: "ComponentC",
mounted() {
console.log(this.$attrs, this.$listeners);
//{name: "六哥", tag: "帅", age: 18} {mouseover: ƒ}
}
};
</script>
复制代码
能够看到咱们利用「$attrs」与「$listeners」在不引入额外的工具或者全局属性,就能够实现从「组件A」到「组件C」之间的数据通讯。若是有相同场景的小伙伴,赶忙用起来吧。
另一点,这里须要注意咱们使用了非 Props 特性,Vue 中组件若是接受非 Props 属性的时候,会把属性渲染到 HTML 的原生标签上。
例如:
<component-b :name="name" :tag="tag"></component-b>
复制代码
渲染后的结果会是
<div class="component-b" name="六哥" tag="帅"></div>
复制代码
显然这不是咱们想要的,咱们的原生标签不须要 「name」与 「tag」这两个属性。那如何避免的呢?很简单,你能够在组件的选项中设置 inheritAttrs: false。
<script>
import ComponentC from "./ComponentC";
export default {
inheritAttrs: false,
name: "ComponentB",
components: { ComponentC }
};
</script>
复制代码
以上就是咱们今天要说的 「$attrs」与「$listeners」,欢迎小伙伴们留言交流,若是以为本文不错,记得点赞哦,码字不容易。