1. 程式人生 > >Vue元件通訊方式全面詳解

Vue元件通訊方式全面詳解

## vue元件通訊方式全面詳解 眾所周知,Vue主要思想就是元件化開發。因為,在實際的專案開發中,肯定會以元件的開發模式進行。形如頁面和頁面之間需要通訊一樣,Vue 元件和元件之間肯定也需要互通有無、共享狀態。接下來,我們就悉數給大家展示所有 Vue 元件之間的通訊方式。 ### 元件關係 ![](https://img2020.cnblogs.com/blog/1364810/202004/1364810-20200402100152682-587394401.png) - App元件和A元件、A元件和B元件、B元件和C元件形成父子關係 - B元件和D元件形成兄弟關係 - App元件和C元件、App和B元件形成了隔代關係(其中的層級可能是多級,既隔多代) ### 元件通訊 ------ 這麼多的元件關係,那麼元件和元件之間又有哪些通訊的方式呢?各種方式的區別又是什麼?適用場景又是什麼呢? #### props和$emit 這種方式是我們日常開發中應用最多的一種方式。 props以單向資料流的形式可以很好的完成父子元件的通訊 所謂單向資料流:就是資料只能通過 props 由父元件流向子元件,而子元件並不能通過修改 props 傳過來的資料修改父元件的相應狀態。至於為什麼這樣做,Vue 官網做出瞭解釋: **\*所有的 prop 都使得其父子 prop 之間形成了一個單向下行繫結:父級 prop 的更新會向下流動到子元件中,但是反過來則不行。這樣會防止從子元件意外改變父級元件的狀態,從而導致你的應用的資料流向難以理解。* **額外的,每次父級元件發生更新時,子元件中所有的 prop 都將會重新整理為最新的值。這意味著你不應該在一個子元件內部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制檯中發出警告。** 正因為這個特性,於是就有了對應的 `$emit`。`$emit` 用來觸發當前例項上的事件。對此,我們可以在父元件自定義一個處理接受變化狀態的邏輯,然後在子元件中如若相關的狀態改變時,就觸發父元件的邏輯處理事件。 ```js let Child = { template: ` `, props: ['msg'], methods: { handleClick() { this.$emit('getChildData', '子元件資料') } }, } let Parent = { data() { return { msg: '小馬哥', val:'' } }, methods: { getChildData(val) { this.val = val; } }, template: `

我是一個父元件

我是{{val}}

`, components: { Child } } let vm = new Vue({ el: '#app', template: ` `, components: { Parent } }) ``` 1. **父傳子**:父元件傳遞msg資料給子元件,通過v-bind繫結msg,子元件中直接可以用props接收繫結的資料 2. **子傳父**:子元件觸發相應的事件,通過$emit觸發事件傳遞資料,父元件中繫結對應的事件,通過$on監聽對應的事件 接收子元件傳遞的資料 #### EventBus-中央事件匯流排 如果想實現兄弟元件之間進行通訊,在專案規模不大的情況下,完全可以使用中央事件匯流排`EventBus`的方式。如果你的專案規模是大中型的,那我們會使用`vuex狀態管理` `EventBus`通過新建一個`Vue`事件`bus`物件,通過`bus.$emit`觸發事件,bus.$on監聽觸發的事件。 ```js Vue.component('A', { template: `

我是A元件

`, data() { return { msg: 'hello 小馬哥' } }, methods: { handleClick() { this.$bus.$emit('globalEvent',this.msg); } }, }) Vue.component('B', { template: `

我是B元件

{{aValue}}

`, data() { return { aValue: '' } }, created () { this.$bus.$on('globalEvent',(val)=>{ this.aValue = val; }) }, }) // 定義中央事件匯流排 let bus = new Vue(); // 將中央事件匯流排賦值給Vue.prototype中,這樣所有元件都能訪問到了 Vue.prototype.$bus = bus; let vm = new Vue({ el: '#app', template: `
`, }) ``` #### $attrs和$listeners 通過 `props`進行元件通訊的方式只適合直接的父子元件,如果父元件A下面有子元件B,元件B下面有元件C,這時如果元件A直接想傳遞資料給元件C那就行不通了! 只能是元件A通過 props 將資料傳給元件B,然後元件B獲取到元件A 傳遞過來的資料後再通過 props 將資料傳給元件C。當然這種方式是非常複雜的,無關元件中的邏輯業務一種增多了,程式碼維護也沒變得困難,再加上如果巢狀的層級越多邏輯也複雜,無關程式碼越多! 針對這樣一個問題,Vue 2.4提供了`$attrs` 和`$listeners`來實現能夠直接讓元件A傳遞訊息給元件C ```js Vue.component('A', { template: `

我是A元件

`, methods: { getCData(val) { alert(val) } }, data() { return { msg: 'hello 小馬哥' } }, }) Vue.component('B', { template: `

我是B元件

`, // props: ['msg'], data() { return { } } }) Vue.component('C', { template: `

我是C元件

{{$attrs.msg}}

`, methods: { handleClick() { this.$emit('getCData', 'C元件的資料') } }, data() { return { } } }) let vm = new Vue({ el: '#app', template: ` `, }) ``` - `$attrs`:包含了父作用域中不被 prop 所識別 (且獲取) 的特性繫結 (`class` 和 `style` 除外)。當一個元件沒有宣告任何 prop 時,這裡會包含所有父作用域的繫結屬性 (class和 `style` 除外),並且可以通過 `v-bind="$attrs"` 傳入內部元件。 - `$listeners`:包含了父作用域中的 (不含 `.native` 修飾器的) `v-on` 事件監聽器。它可以通過 `v-on="$listeners"` 傳入內部元件。 #### provide和inject 在父元件中通過 `provider` 來提供屬性,然後在子元件中通過 inject 來注入變數。不論子元件有多深,只要呼叫了 `inject` 那麼就可以注入在 provider 中提供的資料,而不是侷限於只能從當前父元件的 prop 屬性來獲取資料,只要在父元件的生命週期內,子元件都可以呼叫。這和 React 中的 `Context API` 有沒有很相似! ```js Vue.component('A', { template: `

我是A元件

`, provide:{ a:"祖先A的資料" }, data() { return { msg: 'hello 小馬哥' } }, }) Vue.component('B', { template: `

我是B元件

`, data() { return { } } }) Vue.component('C', { template: `

我是C元件

{{a}}

`, inject:['a'], data() { return { } } }) let vm = new Vue({ el: '#app', template: ` `, }) ``` - 在 `parent` 元件中,通過 `provide` 屬性,以物件的形式向子孫元件暴露了一些屬性 - 在 `child` 元件中,通過 `inject` 屬性注入了 `parent` 元件提供的資料,實際這些通過 `inject` 注入的屬性是掛載到 Vue 例項上的,所以在元件內部可以通過 this 來訪問 > ⚠️ 注意:官網文件提及 provide 和 inject 主要為高階外掛/元件庫提供用例,並不推薦直接用於應用程式程式碼中。 #### $parent和$children 這裡要說的這種方式就比較直觀了,直接操作父子元件的例項。`$parent` 就是父元件的例項物件,而 `$children` 就是當前例項的直接子元件例項了,不過這個屬性值是陣列型別的,且並不保證順序,也不是響應式的。 ```js Vue.component('Parent', { template: `

我是父元件

{{msg}}
`, mounted () { //讀取子元件資料,注意$children並不保證順序,也不是響應式的 console.log(this.$children[0].a) }, data() { return { msg: 'hello 小馬哥' } }, }) Vue.component('Child', { template: `

我是孩子元件

{{myMsg}}

`, methods: { changeValue() { this.$parent.msg = '子元件中的資料' } }, data() { return { myMsg:this.$parent.msg, a:"小馬哥" } } }) let vm = new Vue({ el: '#app', template: ` `, }) ``` #### Vuex狀態管理 Vuex 是狀態管理工具,實現了專案狀態的集中式管理。工具的實現借鑑了 [Flux](https://facebook.github.io/flux/docs/overview.html)、[Redux](http://redux.js.org/)、和 [The Elm Architecture](https://guide.elm-lang.org/architecture/) 的模式和概念。當然與其他模式不同的是,Vuex 是專門為 Vue.js 設計的狀態管理庫,以利用 Vue.js 的細粒度資料響應機制來進行高效的狀態更新。詳細的關於 Vuex 的介紹,你既可以去檢視[官網文件](https://vuex.vuejs.org/zh/),也可以檢視本專欄關於 Vuex 一系列的介紹。