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的形式,對應每一個屬性和取值,可以直接使用例項驗證一下~