inheritAttrs、vm.$listeners 、vm.$attrs 詳解

inheritAttrs

組件的根元素是否繼承不被認作 props的特性,默認true

//父組件
<template>
   <div>
     <child-dom
      :foo="foo"
      :coo="coo"
     >
     </child-dom>
   </div>
</template>
<script>
   import childDom from "../components/Father2-Child";
   export default {
     data() {
        return {
          foo:"Hello, world",
          coo:"Hello,rui"
        }
     },
     components:{childDom},
   }
</script>
//子組件
<template>
   <div>
      <p>foo:{{foo}}</p>
   </div>
</template>
<script>
export default {
 name:'child-dom',
 props:["foo"],
}
</script>

查看DOM結構,結構如下


因為子組件中沒有prop為coo這個屬性,所以繼承了父組件的特性,如果在子組件的props里接收coo則DOM中就不會有這個屬性

在2.4中新增選項inheritAttrs inheritAttrs的默認值為true, 將inheritAttrs的值設為false, 這些默認的行為會禁止掉。

//子組件
<template>
   <div>
      <p>foo:{{foo}}</p>
   </div>
</template>
<script>
export default {
 name:'child-dom',
 props:["foo"],
 inheritAttrs:false,
}
</script>
子組件加了inheritAttrs:false,就不會繼承父組件的特性了

但是通過實例屬性vm.$attrs ,可以將這些特性生效,且可以通過v-bind 綁定到子組件的非根元素上。

vm.$attrs

//父組件
<template>
   <div>
     <child-dom
      :foo="foo"
      :coo="coo"
     >
     </child-dom>
   </div>
</template>
<script>
   import childDom from "../components/Father2-Child";
   export default {
     data() {
        return {
          foo:"Hello, world",
          coo:"Hello,rui"
        }
     },
     components:{childDom},
   }
</script>
//子組件
<template>
   <div>
      <p>foo:{{foo}}</p>
      <p>attrs:{{$attrs}}</p>
      <childDomChild v-bind="$attrs"></childDomChild>
   </div>
</template>
<script>
import childDomChild from '../components/Father2-Child-Child';
export default {
 name:'child-dom',
 props:["foo"],
 inheritAttrs:false,
 components:{childDomChild}
}
</script>
//孫子組件
<template>
  <div>
   <p>coo:{{coo}}</p>
  </div>
</template>
<script>
  export default {
    name:'childDomChild',
    props:["coo"],
    inheritAttrs:false
  }
</script>
輸出結果:子組件和孫子組件通過$attrs獲取到父組件的特性

綜上所述:可以通過$attrs屬性將父組件的數據傳遞給子組件、孫子組件

注意:
$attrs僅包含了父作用域中不作為 prop 被識別的特性 (class 和 style 除外)

那么問題來了,孫子組件的信息怎么同步給父組件呢?下面我們就來解決這個問題

vm.$listeners

vue2.4版本新增了$listeners屬性,它是一個對象,里面包含了作用在這個組件上的所有監聽器,有了這個$listeners屬性,你就可以配合 v-on="$listeners"將所有的事件監聽器指向這個組件的某個特定的子元素。

我們在子組件上 綁定v-on=”$listeners”, 就可以在父組件中監聽孫子組件觸發的事件,就能把孫子組件發出的數據,傳遞給父組件。

//父組件
<template>
 <div>
    {{coo}}
   <child-dom
    :foo="foo"
    :coo="coo"
     @upRocket="reciveRocket">
   </child-dom>
 </div>
</template>
<script>
 import childDom from "../components/Father2-Child";
 export default {
   name:'demoNo',
   data() {
        return {
            foo:"Hello, world",
            coo:"Hello,rui"
        }
    },
    components:{childDom},
    methods:{
        reciveRocket(ev){
            this.coo = ev;//改變數據
            console.log(this.coo)
        }
    }
}
</script>
//子組件
<template>
    <div>
        <p>foo:{{foo}}</p>
        <p>attrs:{{$attrs}}</p>
        <childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
    </div>
</template>
<script>
import childDomChild from '../components/Father2-Child-Child';
export default {
    name:'child-dom',
    props:["foo"],
    inheritAttrs:false,
    components:{childDomChild}
}
</script>
//孫子組件
<template> 
    <div>
    <p>coo:{{coo}}</p>
    <button @click="startUpRocket">我要發射火箭</button>
    </div>
</template>
<script>
 export default {
    name:'childDomChild',
    props:['coo'],
    methods:{
        startUpRocket(){
            this.$emit("upRocket",'簡單我的簡單');
        }      
    }
 }
</script>
輸出結果

點擊“我要發射火箭”后的結果

至此,孫子組件向父組件傳遞數據的問題也解決了

綜上所述:vm.$attrsvm.$listeners 可以解決“父組件”和“子組件”、“孫子組件”、“曾孫子組件”等后代組件的通訊問題

  • inheritAttrs

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

注意:這個選項不影響 class 和 style 綁定。

  • vm.$attrs

包含了父作用域中不作為 prop 被識別的特性綁定 (class 和 style 除外)。當一個組件沒有聲明任何 prop 時,這里會包含所有父作用域的綁定 (class 和 style 除外),并且可以通過 v-bind="$attrs" 傳入內部組件——在創建多級的組件時非常有用。

  • vm.$listeners

包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它可以通過 v-on="$listeners"傳入內部組件——在創建更高層次的組件時非常有用。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容