$attrs和$listeners

$attrs$listeners的主要應用是實現多層嵌套傳遞。
在這裏插入圖片描述
組件A與組件B通信一般都會使用組件B中轉,即A傳遞給B,B再給C,但是如果A到C組件之間嵌套的組件過多,需要傳遞的事件和屬性較多,會導致代碼繁瑣,代碼維護困難。在vue2.4中,爲了解決該需求,引入了$attrs$listeners,新增了inheritAttrs選項。

$attrs的使用

官方定義:
包含了父作用域中不作爲prop 被識別 (且獲取) 的特性綁定 (classstyle除外)。當一個組件沒有聲明任何 prop 時,這裏會包含所有父作用域的綁定 (classstyle除外),並且可以通過 v-bind="$attrs" 傳入內部組件——在創建高級別的組件時非常有用。
(好抽象一臉懵逼。。。)
$attrs只代表的是那些沒有被聲明爲props的屬性,如果某個prop被子組件中聲明瞭(就是這個屬性已經在子組件的props中了),在子組件中的$attr會把聲明的prop剔除。
個人理解: 一個組件在父組件中被引用,$attrs就是組件標籤上的靜態屬性值(attr)和動態屬性值(:attr)的對象集合,這個集合不包含classstyle和事件屬性

// 父組件
<child-com class="com" name="attr" :foo="foo" :boo="boo" :coo="coo" :doo="doo" @click="test"></child-com>
...
data() {
  return {
    foo: 'Hello World!',
    boo: 'Hello Javascript!',
    coo: 'Hello Vue',
    doo: 'Last'
  }
},
...

// child-com.vue
 export default {
  name: 'childCom',
  components: {
    childCom2
  },
  created() {
    console.log(this.$attrs) // {name: "attr", foo: "Hello World!", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}

如果子組件聲明瞭$prop$attrs中與$props相同的屬性會被移除

// child-com.vue
 export default {
  name: 'childCom',
  props: ['foo'], // foo被聲明
  components: {
    childCom2
  },
  created() {
    console.log(this.$attrs) // {name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}

如果childCom裏的子組件還用到foo,可以繼續將foo傳給子組件

<template>
  <div>
    <p>foo: {{foo}} </p>
    <child-com2 :foo="foo" v-bind="$attrs"></child-com2>
  </div>
</template>

<script>
const childCom2 = () => import('./childCom2.vue')
export default {
  name: 'childCom1',
  props: ['foo'], // foo作爲props屬性綁定
  inheritAttrs: false,
  components: {
    childCom2
  },
  created() {
    console.log(this.$attrs) // {name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}
</script>

//childCom2.vue
created() {
    console.log(this.$attrs) // {foo: "Hello World!", name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }

inheritAttrs要設置成false還是true(默認)看下圖就知道
在這裏插入圖片描述
在這裏插入圖片描述
$props比較
$props必須在組件中註冊了props才能用拿到值,所以在嵌套層級比較深的組件中$attrs拿值更加便捷

$listeners的使用

包含了父作用域中的 (不含 .native 修飾器的) v-on 事件監聽器。它可以通過v-on=”$listeners”傳入內部組件。
歸納起來也是兩點:

  • $listeners是組件的內置屬性,它的值是父組件(不含.native修飾器的) v-on事件監聽器。
  • 組件可以通 過在自己的子組件上使用v-on=”$listeners”,進一步把值傳給自己的子組件。如果子組件已經綁定$listener中同名的監聽器,則兩個監聽器函數會以冒泡的方式先後執行。
    父組件:
 <template>
    <div class="test">
        <child  v-bind="{name, sex, age}" v-on="{changeName,changeAge}"></child>
    </div>
</template>

<script>
import child from './child'

export default {
    data() {
        return {
          name: '張三',
          sex: '男',
          age: 11,
        }
    },
    components: {
        child
    },
    methods: {
        changeName(name) {
            this.name = name
        },
        changeAge(age) {
            this.age = age
        }
    }
}
</script>

子組件child.vue

<template>
    <div class="child">
        child組件的$attrs {{$attrs}}
        <child-child v-bind="$attrs" v-on="$listeners" @showAttrs="showAttrs"></child-child>
    </div>
</template>

<script>
import childChild from  './child-child'
export default {
    name: "child",
    props: ['name'],
    inheritAttrs: false,
    created() {
        console.log('child', this.$listeners) 
    },
    components: {
        childChild
    },
    methods: {
        showAttrs() {
            console.log(this.$attrs)
        }
    }
}
</script>

孫子組件:child-child.vue

<template>
    <div class="child-child">
        child-child組件的$attrs {{$attrs}}
    </div>
</template>

<script>
export default {
    name: "child-child",
    inheritAttrs: false,
    created() {
      console.log('child-child',this.$listeners)  
    }
}
</script>

打印結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章