Vue2.4 $attrs、$listeners、inheritAttrs的使用

在開始介紹之前先看下vue官方文檔對(duì) $attrs$listeners的解釋:

vm.$attrs
包含了父作用域中不作為 prop 被識(shí)別 (且獲取) 的特性綁定 (class 和 style 除外)。當(dāng)一個(gè)組件沒有聲明任何 prop 時(shí),這里會(huì)包含所有父作用域的綁定 (class 和 style 除外),并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件——在創(chuàng)建高級(jí)別的組件時(shí)非常有用。
vm.$listeners
包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監(jiān)聽器。它可以通過 v-on="$listeners" 傳入內(nèi)部組件——在創(chuàng)建更高層次的組件時(shí)非常有用。

講真,我看了幾遍也是沒看懂,既然如此那就舉個(gè)栗子來說明吧,先看如下圖組件多級(jí)嵌套的情況:

圖1

如圖所示,A B C組件的嵌套關(guān)系如圖所示,如果從數(shù)據(jù)從A組件到B組件則用props屬性即可,將更新的數(shù)據(jù)傳回A組件則采用$emit觸發(fā)A組件自定義函數(shù)即可,那么直接從A組件到C組件如何傳遞數(shù)據(jù)呢?
方案1:采用Vuex進(jìn)行統(tǒng)一的狀態(tài)管理。如果項(xiàng)目不是很大,組件間的全局共享狀態(tài)不多,則使用vuex反而復(fù)雜
方案2:將A組件的數(shù)據(jù)傳到B組件在從B組件傳到C組件。會(huì)造成代碼繁瑣維護(hù)困難等。
在vue2.4中,為了解決該需求,引入了$attrs$listeners , 新增了inheritAttrs 選項(xiàng)。

<!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">點(diǎn)擊更新數(shù)據(jù)到父組件</button>
                    <button type="button" @click="changeChildData">點(diǎn)擊更新數(shù)據(jù)到Child組件</button>
                    </div>`,
                props: ['coo','ceo'],//即使props中加入foo也無法獲取值,因?yàn)閒oo屬性已在Child組件注冊(cè)
                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中未注冊(cè)父組件傳遞過來的屬性,即除了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: '父組件內(nèi)容foo',
                        coo: '父組件內(nèi)容coo',
                        ceo: '父組件內(nèi)容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ù)據(jù)從A組件到B組件依然通過父組件自定義屬性,子組件注冊(cè)props接受屬性值的形式。
不同的是在Child組件中綁定了$attrs$listeners,而在Child組件props中注冊(cè)了父組件傳遞過來的foo屬性,在GrandSon組件的props中注冊(cè)了coo、ceo屬性,那么$attrs則起到將coo ceo屬性從父組件傳到孫組件的作用,同樣如果要在孫組件改變數(shù)據(jù)后回傳到父組件,只需要在Child組件中綁定$listeners即可,依然是通過父組件自定義事件,孫組件通過$emit觸發(fā)函數(shù)。

接下來介紹inheritAttrs:

inheritAttrs:默認(rèn)情況下父作用域的不被認(rèn)作 props 的特性綁定 (attribute bindings) 將會(huì)“回退”且作為普通的 HTML 特性應(yīng)用在子組件的根元素上。當(dāng)撰寫包裹一個(gè)目標(biāo)元素或另一個(gè)組件的組件時(shí),這可能不會(huì)總是符合預(yù)期行為。通過設(shè)置 inheritAttrs 到 false,這些默認(rèn)行為將會(huì)被去掉。而通過 (同樣是 2.4 新增的) 實(shí)例屬性 $attrs 可以讓這些特性生效,且可以通過 v-bind 顯性的綁定到非根元素上。

執(zhí)行上面代碼查看子組件的DOM元素,如下圖:

image.png

簡單來說就是,當(dāng)子組件的props中未注冊(cè)父組件傳遞過來的屬性時(shí):
當(dāng)設(shè)置inheritAttrs: true(默認(rèn))時(shí),子組件頂層標(biāo)簽會(huì)渲染出父組件傳遞過來的屬性,
當(dāng)設(shè)置inheritAttrs: true時(shí),子組件頂層標(biāo)簽不會(huì)渲染父組件傳遞過來的屬性;
無論inheritAttrs為true或者false,子組件中都能通過$attrs屬性獲取到父組件中傳遞過來的屬性,參考上面的console.log(this. $attrs)打印出來的值即可。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容