前言
vue通信手段有很多種炸庞,props/emit、vuex翠勉、event bus妖啥、provide/inject 等。還有一種通信方式对碌,那就是 $attrs
和 $listeners
荆虱,這種方式很優(yōu)雅,使用起來也不賴朽们。下面例子都會(huì)通過父(index)怀读、子(child)、孫子(grandson)华坦,三者的關(guān)系來說明使用方式愿吹。
$attrs
官方解釋:
包含了父作用域中不作為 prop 被識(shí)別 (且獲取) 的 attribute 綁定 (class 和 style 除外)。當(dāng)一個(gè)組件沒有聲明任何 prop 時(shí)惜姐,這里會(huì)包含所有父作用域的綁定 (class 和 style 除外)犁跪,并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件——在創(chuàng)建高級(jí)別的組件時(shí)非常有用椿息。
我的理解:
接收除了props聲明外的所有綁定屬性(class、style除外)
index.vue
<child class="arrts" id="10" age="20" sex="男" ></child>
<!--在 子組件中展示 $arrts:{ "age": "20", "sex": "男" } 坷衍;class和style 特殊的不會(huì)被綁定 -->
child.vue
<template>
<div class="attrs-one-view">
<p>$arrts:{{ $attrs }}</p> <!-- { "age": "20", "sex": "男" } -->
<div>prop->id: {{ id }}</div> <!-- 10 -->
</div>
</template>
<script>
export default {
props: {
id: {
type: String,
},
},
};
</script>
圖解:
解釋:
由于child.vue 在 props 中聲明了 id 屬性寝优,$attrs
中只有age、gender兩個(gè)屬性枫耳,輸出結(jié)果為:
{ "age": "20", "sex": "男" }
$attrs 里面接收的是 除了porps里面定義屬性之外的值
child子組件可以通過 v-bind="$attrs" 定義到grandson.vue 上乏矾,把 index.vue 中定義的屬性傳遞到"孫組件"上。讓 grandson.vue 也能訪問到父組件的屬性迁杨,這在傳遞多個(gè)屬性時(shí)會(huì)顯得很便捷钻心,而不用一條條的進(jìn)行綁定。
如果想要添加其他屬性铅协,可繼續(xù)綁定屬性捷沸。但要注意的是,繼續(xù)綁定的屬性和 $attrs 中的屬性有重復(fù)時(shí)狐史,繼續(xù)綁定的屬性優(yōu)先級(jí)會(huì)更高
$listeners
如果$attrs
是操作父子傳參的痒给,那$listeners
就是操作父組件傳遞子組件方法的
官方解釋:
包含了父作用域中不作為 prop 被識(shí)別 (且獲取) 的 attribute 綁定 (class 和 style 除外)。當(dāng)一個(gè)組件沒有聲明任何 prop 時(shí)骏全,這里會(huì)包含所有父作用域的綁定 (class 和 style 除外)苍柏,并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件——在創(chuàng)建高級(jí)別的組件時(shí)非常有用。
我的理解
-
$listeners
和$attrs
類似姜贡,只不過$attrs
是v-bind 而$listeners
是用v-on 而已试吁, - 接收除了帶有.native事件修飾符的所有事件監(jiān)聽器
index.vue
<template>
<child @getInfo="getInfo" @getMessage.native="getMessage"></child>
</template>
<script>
export default {
components: { child, },
methods: {
getInfo(val) {
console.log("getInfo事件來源于index.vue" + val);
},
getMessage(val) {
console.log("getMessage事件來源于index.vue" + val);
},
},
};
</script>
child.vue
<template>
<div class="child-view">
<grandson v-on="$listeners" @getMessage="getMessage" ></grandson>
</div>
</template>
<script>
export default {
components: { grandson, },
created() {
console.log(this.$listeners, '====listeners');
},
};
//打印結(jié)果: 因?yàn)樵趇ndex.vue中g(shù)etMessage有native修飾,所以不會(huì)觸發(fā)
// {getInfo: ?}getInfo: ? invoker()[[Prototype]]: Object '====listeners'
grandson.vue
<script>
export default {
created() {
console.log(this.$listeners, "====listeners");
},
};
</script>
//打印結(jié)果:
// {getInfo: ?, getMessage: ?}getInfo: ? invoker()getMessage: ? invoker()[[Prototype]]: Object '====listeners'
- 同
attrs
屬性一樣鲁豪,可以通過v-on="$listeners"
潘悼,將事件監(jiān)聽器繼續(xù)向下傳遞,讓grandson.vue
訪問到事件爬橡,且可以使用$emit
觸發(fā) parent.vue 的函數(shù)治唤。 -
如果想要添加其他事件監(jiān)聽器,可繼續(xù)綁定事件糙申。但要注意的是宾添,繼續(xù)綁定的事件和 $listeners 中的事件有重復(fù)時(shí),不會(huì)被覆蓋柜裸。
即: 當(dāng) grandson.vue 觸發(fā) getMessage 事件時(shí)缕陕,child.vue 和 parent.vue 的事件都會(huì)被觸發(fā),觸發(fā)順序類似于冒泡疙挺,先到 child.vue 再到 parent.vue扛邑。
觸發(fā)冒泡事件
解釋:當(dāng)index.vue 和child.vue 綁定相同的事件的時(shí)候,grandson.vue 會(huì)先觸發(fā)child的事件后觸發(fā)index.vue 的事件铐然,所以寫代碼時(shí)事件名稱不要重復(fù)蔬崩。
代碼地址:碼云 vue-question 組件通訊
參考文檔:Vue - 組件通信之a(chǎn)ttrs恶座、listeners