在開始介紹之前先看下vue官方文檔對 $attrs
和 $listeners
的解釋:
vm.$attrs
包含了父作用域中不作為 prop 被識別 (且獲取) 的特性綁定 (class 和 style 除外)挤茄。當一個組件沒有聲明任何 prop 時如叼,這里會包含所有父作用域的綁定 (class 和 style 除外),并且可以通過v-bind="$attrs"
傳入內部組件——在創(chuàng)建高級別的組件時非常有用穷劈。
vm.$listeners
包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽器笼恰。它可以通過v-on="$listeners"
傳入內部組件——在創(chuàng)建更高層次的組件時非常有用。
講真歇终,我看了幾遍也是沒看懂社证,既然如此那就舉個栗子來說明吧,先看如下圖組件多級嵌套的情況:
如圖所示评凝,A B C組件的嵌套關系如圖所示追葡,如果從數(shù)據從A組件到B組件則用props屬性即可,將更新的數(shù)據傳回A組件則采用
$emit
觸發(fā)A組件自定義函數(shù)即可奕短,那么直接從A組件到C組件如何傳遞數(shù)據呢宜肉?方案1:采用Vuex進行統(tǒng)一的狀態(tài)管理。如果項目不是很大翎碑,組件間的全局共享狀態(tài)不多谬返,則使用vuex反而復雜
方案2:將A組件的數(shù)據傳到B組件在從B組件傳到C組件。會造成代碼繁瑣維護困難等日杈。
在vue2.4中遣铝,為了解決該需求佑刷,引入了
$attrs
和$listeners
, 新增了inheritAttrs
選項翰蠢。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<App />
</div>
<script src="../node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
let GrandSon = {
template: `<div>這是孫組件项乒,獲取的父組件信息為:{{coo}} {{ceo}}
<button type="button" @click="changeData">點擊更新數(shù)據到父組件</button>
<button type="button" @click="changeChildData">點擊更新數(shù)據到Child組件</button>
</div>`,
props: ['coo','ceo'],//即使props中加入foo也無法獲取值啰劲,因為foo屬性已在Child組件注冊
data(){
return {
}
},
methods: {
changeData(){
this.$emit('updateData', {
name: 'zhang',
age: '22'
})
},
changeChildData(){
this.$emit('updateChildData', {
name: 'qianfeng'
})
}
},
}
let Child = {
props: ['foo'],
inheritAttrs: true,
template:`<div>這是子組件,獲取的父組件信息為:{{foo}}
<GrandSon v-bind="$attrs" v-on="$listeners" @updateChildData="updateChildData" />
</div>`,
components: {
GrandSon,
},
mounted(){
//$attrs屬性獲取子組件的props中未注冊父組件傳遞過來的屬性梁沧,即除了foo以外的屬性
console.log('this.$attrs:', this.$attrs)
},
methods: {
updateChildData(data){
console.log(data)
}
}
}
let App = {
template: '<div>這是父組件<Child :foo="foo" :coo="coo" :ceo="ceo" @updateData="updateData" /></div>',
data(){
return {
foo: '父組件內容foo',
coo: '父組件內容coo',
ceo: '父組件內容ceo',
}
},
components: {
Child,
},
methods: {
updateData(data){
console.log(data)
},
},
}
let vm = new Vue({
el: '#app',
data(){
return {}
},
components: {
App,
},
})
</script>
</body>
</html>
如上述代碼,App代表A組件蝇裤,Child代表B組件廷支,GeandSon代表C組件,數(shù)據從A組件到B組件依然通過父組件自定義屬性栓辜,子組件注冊props接受屬性值的形式恋拍。
不同的是在Child組件中綁定了$attrs
和$listeners
,而在Child組件props中注冊了父組件傳遞過來的foo屬性,在GrandSon組件的props中注冊了coo藕甩、ceo屬性施敢,那么$attrs
則起到將coo ceo屬性從父組件傳到孫組件的作用,同樣如果要在孫組件改變數(shù)據后回傳到父組件狭莱,只需要在Child組件中綁定$listeners
即可僵娃,依然是通過父組件自定義事件,孫組件通過$emit
觸發(fā)函數(shù)腋妙。
接下來介紹inheritAttrs:
inheritAttrs:
默認情況下父作用域的不被認作 props 的特性綁定 (attribute bindings) 將會“回退”且作為普通的 HTML 特性應用在子組件的根元素上默怨。當撰寫包裹一個目標元素或另一個組件的組件時,這可能不會總是符合預期行為骤素。通過設置 inheritAttrs 到 false匙睹,這些默認行為將會被去掉。而通過 (同樣是 2.4 新增的) 實例屬性 $attrs 可以讓這些特性生效济竹,且可以通過 v-bind 顯性的綁定到非根元素上痕檬。
執(zhí)行上面代碼查看子組件的DOM元素,如下圖:
簡單來說就是送浊,當子組件的props中未注冊父組件傳遞過來的屬性時:
當設置
inheritAttrs: true
(默認)時梦谜,子組件頂層標簽會渲染出父組件傳遞過來的屬性,當設置
inheritAttrs: true
時罕袋,子組件頂層標簽不會渲染父組件傳遞過來的屬性改淑;無論
inheritAttrs
為true或者false,子組件中都能通過$attrs
屬性獲取到父組件中傳遞過來的屬性,參考上面的console.log(this. $attrs)
打印出來的值即可浴讯。