1. 程式人生 > 實用技巧 >vue中使用v-bind="$attrs"和v-on="$listeners"進行多層元件通訊

vue中使用v-bind="$attrs"和v-on="$listeners"進行多層元件通訊

vue元件之間通訊,我們可以使用props和vuex兩種方式,但是vuex太重,props在多級元件中使用又太麻煩,vue2.4版本提供了另一種方法,使用v-bind="$attrs",將父元件中不被認為 props特性繫結的屬性傳入子元件中,通常配合 interitAttrs 選項一起使用。

例如下面的層級關係

<top>
  <center>
    <bottom>
    </bottom>
  </center>
</parent>

如果top元件要和bottom元件進行通訊,下面有三種方式可以實現

  1.通過props和$emit的方式,需要通過center作為中轉,top把值傳給center,center再把值傳給bottom,或者bottom把值傳給center,center在傳給top

  2.使用vuex,但是這兩個元件的狀態可能不是全域性狀態

  3.使用中央事件匯流排bus

使用前兩種方式可能都不太理想,這裡來講一下另一種方式

  先看一下程式碼片段

top元件,傳遞了name,age,gender,sdf四個屬性到子元件center,然後接收了兩個isClick()和asd()方法

<template>
  <section>
    <centers
      name="name"
      age="18"
      gender="666"
      sdf="asd"
      @isClick="isClick"
      @asd="asd"
    ></centers>
  </section>
</template>
<script>
  import centers from '~/components/center';
  export default {
    components: {
      centers
    },
    methods: {
      asd() {
        console.log(999);
      },
      isClick() {
        console.log(666);
      }
    }
  };
</script>

center元件,只接收了name和age兩個屬性,其他屬性沒有接收,使用v-bind="$attrs"屬性,vm.$attrs是一個屬性,其包含了父作用域中不作為 prop 被識別 (且獲取) 的特性繫結 (class 和 style 除外)。這些未識別的屬性可以通過v-bind="$attrs"傳入內部元件。未識別的事件可通過v-on="$listeners"傳入(.native綁原生事件是沒用的)。

<template>
  <section>
    <div class="mt-10">
      <bottom v-bind="$attrs" v-on="$listeners" />
    </div>
  </section>
</template>

<script>
  import bottom from '~/components/bottom';
  export default {
    components: {
      bottom
    },
    props: {
      name: {
        type: String,
        default: 'default'
      },
      age: {
        type: String,
        default: 'default'
      }
    }
  };
</script>

bottom元件,我們只接收了gender屬性,但是這個屬性是其父元件center使用v-bind="$attrs"從top元件接收到的,center元件本身並沒有使用props接收這個屬性,但是bottom屬性確可是使用

<template>
  <section>
    <div>
      {{ $attrs['gender'] }}  在$attrs裡面只會有props沒有註冊的屬性
      <br>
      {{ gender }}
    </div>
  </section>
</template>

<script>
  export default {
    props: {
      gender: {
        type: String,
        default: ''
      }
    },
    mounted() {
      console.log(this.$attrs);
      console.log(this.$listeners);
      this.$listeners.isClick();
      this.$listeners.asd();
    }
  };
</script>

總結

1.v-bind="$props": 可以將父元件的所有props下發給它的子元件,子元件需要在其props:{} 中定義要接受的props。

  vm.$props: 當前元件接收到的 props 物件。Vue 例項代理了對其 props 物件屬性的訪問。

2.v-bind="$attrs": 將呼叫元件時的元件標籤上繫結的非props的特性(class和style除外)向下傳遞。在子元件中應當新增inheritAttrs: false(避免父作用域的不被認作props的特性繫結應用在子元件的根元素上)。

  vm.$attrs:包含了父作用域中不作為 prop 被識別 (且獲取) 的特性繫結 (class 和 style 除外)。當一個元件沒有宣告任何 prop 時,這裡會包含所有父作用域的繫結 (class 和 style 除外),並且可以通過 v-bind="$attrs" 傳入內部元件——在建立高級別的元件時非常有用。

3.v-on="將父元件標籤上的自定義事件向下傳遞其子元件可以直接通過emit(eventName)的方式呼叫。

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

4.舉例說明:

  4.1.如上例項程式碼中,top元件傳值給center可以全部不接收,然後直接通過v-bind="$attrs"傳給bottom,然後bottom元件直接使用props接收top傳過來的所有屬性

  4.2.在別人元件的基礎上進行二次封裝的時候,定義好自己的屬性,然後在自己的元件上直接傳值,然後通過v-bind="$attrs"把值傳給別人的元件即可,例如

<template>
  <div>
    <el-button v-bind="$attrs">確定</el-button>
  <div>
</template>
 
// 父元件使用
<my-button type='primary' size='mini'/>

5.vm.$attrs和vm.$listeners獲取到的值都是json的形式,對應每一個屬性和取值,可以直接使用例項驗證一下~