咱們都知道 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」,歡迎小夥伴們留言交流,若是以爲本文不錯,記得點贊哦,碼字不容易。