Vue中父與孫組件的傳遞


前言#

多級組件嵌套需要傳遞數據時,通常使用的方法是通過vuex。如果僅僅是傳遞數據,而不做中間處理,使用 vuex 處理,未免有點殺雞用牛刀。Vue 2.4 版本提供了另一種方法:

使用 v-bind=”$attrs”, 將父組件中不被認為 props特性綁定的屬性傳入子組件中,配合 interitAttrs 選項一起使用。

之所以要提到這兩個屬性,是因為兩者的出現使得組件之間跨組件的通信在不依賴 vuex 和事件總線的情況下變得簡潔,業務清晰。

首先分析以下應用場景:

img

A 組件與 B 組件之間的通信: (父子組件)#

如上圖所示,A、B、C三個組件依次嵌套,按照 Vue 的開發習慣,父子組件通信可以通過以下方式實現:

A to B 通過props的方式向子組件傳遞,
B to A 通過在 B 組件中 $emit

A 組件與 C 組件之間的通信: (跨多級的組件嵌套關系)#

如上圖,A 組件與 C 組件之間屬於跨多級的組件嵌套關系,以往兩者之間如需實現通信,往往通過以下方式實現:

  1. 借助 B 組件的中轉,從上到下props依次傳遞,從下至上,$emit事件的傳遞,達到跨級組件通信的效果
  2. 借助Vuex的全局狀態共享
  3. Vue Bus,使用Vue的實例,實現事件的監聽和發布,實現組件之間的傳遞。

第一種通過props和$emit的方式,使得組件之間的業務邏輯臃腫不堪,B組件在其中僅僅充當的是一個中轉站的作用。
第二種 Vuex的方式,某些情況下似乎又有點大材小用的意味,(僅僅是想實現組件之間的一個數據傳遞,並非數據共享的概念)。
第三種情況的使用在實際的項目操作中發現,如不能實現很好的事件監聽與發布的管理,往往容易導致數據流的混亂,在多人協作的項目中,不利於項目的維護。

$attrs以及$listeners的出現解決的就是第一種情況的問題,B組件在其中傳遞props以及事件的過程中,不必在寫多余的代碼,僅僅是將$attrs以及$listeners向上或者向下傳遞即可。

示例代碼
如下所示:

父組件(father.vue)

<template>
   <div id="app">
     <son
       :name="name"
       :age="age"
       @getName="getName" 
       @getAge="getAge"> 
     </son>
   </div>
</template>
<script>
   import son from './son.vue';
   export default {
     data () {
       return {
          name:'vicer',
          age:18
       };
     },
     components: { son },
     methods: {
       getName () {
         console.log(this.name);
       },
       getAge () {
         console.log(this.age);
       }
     }
   };
</script>

控制台查看結果:
'vicer'

18

子組件(son.vue)

<template>
   <div>
     <p>我是子組件:</p>
     <p>props: {{name}}</p>    <!-- 從父組件得到props -->
     <p>$attrs: {{$attrs}}</p>        <!-- 被跨級傳遞的屬性 -->
     
     <hr>
   <!-- 跨級傳遞事件:在中間組件(B組件)綁定了$listeners屬性,孫組件中能直接觸發父組件中的getName事件-->
   <!-- 跨級傳遞數據:通過在中間組件綁定$attrs屬性,C組件可以直接獲取到A組件中傳遞下來的props-->
 		<grandson v-bind="$attrs" v-on="$listeners"></grandson>
 </div>
</template>
<script>
   import grandson from './grandson.vue';
   export default {
    props: ['name'],
    data () {
      return {};
    },
    inheritAttrs: false,
    components: { grandson },
    mounted () {
      this.$emit('getName');		//vicer
    }
 	};
</script>

結果:
我是子組件:
props: vicer
$attrs: { "age": 18}

孫組件 (grandson.vue)

<template>
   <div>
     <p>我是孫組件:</p>
     <p>props: {{age}}</p>
     <p>$attrs: {{$attrs}}</p>
		 <button @click="$listeners.getAge">按鈕1</button>	<!-- 跨級發送事件方式一 -->
     <button @click="sendEvent">按鈕2</button>	<!-- 跨級發送事件方式二 -->
     <hr>
   </div>
</template>
<script>
   export default {
  	 props: ['age'],
     mounted() {
      console.log(this.$listeners)		//{getName: ƒ, getAge: ƒ}
     },
     data () {
        return {};
     },
     methods () {
       sendEvent(){
         this.$emit('getAge');     
       }
     }
   };
</script>

結果:
我是孫組件:
props: 18
$attrs: {}

知識點總結#

$attrs

當在父組件向子組件傳遞數據時,並且子組件不聲明props,則$attrs包含所有屬性的集合。並且會在子組件的根標簽中聲明被傳遞的屬性。如:<div name='vicer'></div>

在子組件引入孫組件,並在子組件聲明屬性v-bind="$attrs",則可以跨級傳遞參數

注意:如果子組件聲明了props,則$attrs只包含不被聲明的props

$listeners

在子組件引入孫組件,並在子組件中聲明v-on="$listeners"屬性,則孫組件可跨級emit事件,讓父組件監聽到

// 跨級發送事件方式一 
<button @click="$listeners.testC">按鈕</button>	

//跨級發送事件方式二
mounted () {
  this.$emit('testC');     
}

inheritAttrs

當在父組件向子組件傳遞數據時,並且子組件不聲明props,默認在

但從父級傳遞過來的屬性子組件不可能完全都用到,有一部分可能要傳給孫組件,這時就要在子組件中聲明inheritAttrs=false,不繼承屬性,並通過v-bind=“$attrs"傳遞給孫組件

上述特性的使用,完全可以降低在不使用Vuex以及Vue bus的情況下,組件跨級傳遞復雜度。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM