1. 程式人生 > >Vue2.4中$attrs和$listeners的使用-學習筆記

Vue2.4中$attrs和$listeners的使用-學習筆記

首先我們來看下面的一張圖,圖中表示一個多級元件巢狀的情形。

現在我們來討論一種情況,A元件與C元件怎麼通訊,我們有多少種解決方案?

  1. 我們使用VueX來進行資料管理,但是如果專案中多個元件共享狀態比較少,專案比較小,並且全域性狀態比較少,那使用VueX來實現該功能,並沒有發揮出VueX的威力。
  2. 使用B來做中轉站,當A元件需要把資訊傳給C元件時,B接受A元件的資訊,然後利用屬性傳給C元件,這是一種解決方案,但是如果巢狀的元件過多,會導致程式碼繁瑣,程式碼維護比較困難;如果C中狀態的改變需要傳遞給A, 使用事件系統一級級往上傳遞 。本來
  3. 自定義一個Vue 中央資料匯流排,這個情況適合碰到元件跨級傳遞訊息,但是使用VueX感覺又有點浪費的專案中,但是缺點是,碰到多人合作時,程式碼的維護性較低,程式碼可讀性低

在很多開發情況下,我們只是想把A元件的資訊傳遞給C元件,如果使用props 繫結來進行資訊的傳遞,雖然能夠實現,但是程式碼並不美觀。

在vue2.4中,為了解決該需求,引入了$attrs 和$listeners , 新增了inheritAttrs 選項。 在版本2.4以前,預設情況下父作用域的不被認作props的屬性屬性百年孤獨,將會“回退”且作為普通的HTML特性應用在子元件的根元素上。如下列的例子

父元件demo程式碼如下

<template>
   <div>
     <child-dom
      :foo="foo"
      :coo="foo"
     >
     </child-dom>
   </div>
</template>
<script>
   import childDom from "./ChildDom.vue";
   export default {
     data() {
        return {
          foo:"Hello, world",
          coo:"Hello,rui"
        }
     },
     components:{childDom},
   }
</script>

子元件child-dom程式碼如下

<template>
   <div>
      <p>foo:{{foo}}</p>
   </div>
</template>
<script>
export default {
 name:'child-dom'
 props:["foo"]
}
</script>

當顯示父元件時,檢視Dom結構,結構如下

在2.4中新增選項inheritAttrs  inheritAttrs的預設值為true, 將inheritAttrs的值設為false, 這些預設的行為會禁止掉。但是通過例項屬性$attrs 

,可以將這些特性生效,且可以通過v-bind 繫結到子元件的非根元素上。

修改子元件程式碼如下

<template>
   <div>
      <p>foo:{{foo}}</p>
      <p>attrs:{{$attrs}}</p>
      <childDomChild v-bind="$attrs"></childDomChild>
   </div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
 name:'child-dom'
 props:["foo"],
 inheritAttrs:false,
}
</script>

新增子元件 childDomChild

<template>
  <div>
   <p>coo:{{coo}}</p>
  </div>
</template>
<script>
  export default {
    name:'childDomChild'
    props:["coo"],
    inheritAttrs:false
  }
</script>

輸出的結果如下

從上面的程式碼,可以看出使用$attrs ,inheritAttrs 屬性 能夠使用簡潔的程式碼,將A元件的資料傳遞給C元件 ,該場景的使用範圍還是挺廣的。

此時我們又想到了一個問題,c元件的資訊,怎麼同步給a元件呢? 

vue2.4版本新增了$listeners 屬性,我們在b元件上 繫結 v-on=”$listeners”, 在a元件中,監聽c元件觸發的事件。就能把c元件發出的資料,傳遞給a元件。

A元件程式碼更新如下

<template>
 <div>
   <child-dom
    :foo="foo"
    :coo="coo"
     v-on:upRocket="reciveRocket"
   >
   </child-dom>
 </div>
</template>
<script>
 import childDom from "@/components/ChildDom.vue";
 export default {
   name:'demoNo',
   data() {
     return {
       foo:"Hello, world",
        coo:"Hello,rui"
    }
  },
 components:{childDom},
 methods:{
   reciveRocket(){
      console.log("reciveRocket success")
   }
 }
}
</script>

b元件更新如下

<template>
 <div>
 <p>foo:{{foo}}</p>
 <p>attrs:{{$attrs}}</p>
 <childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
 </div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
 name:'child-dom'
 props:["foo"],
 inheritAttrs:false,
}
</script>

c元件更新如下

<template> 
 <div>
 <p>coo:{{coo}}</p>
 <button @click="startUpRocket">我要發射火箭</button>
 </div>
</template>
<script>
 export default {
 name:'childDomChild',
 props:['coo'],
 methods:{
 startUpRocket(){
 this.$emit("upRocket");
 console.log("startUpRocket")
 }
 }
 }
</script>

執行效果如下

現在我們應該清楚了$attrs,$listernersinheritAttrs 的作用了吧