vue 解決兄弟元件、跨元件深層次的通訊問題
兄弟元件之間的通訊同樣是在專案中經常會遇到的元件間的通訊問題之一, 這種問題的最根本方法就是: 把兄弟元件內部的變數提升到一箇中央倉庫。
藉助父級元件鏈式互動
使子元件1 通過 $emit
通知父級, 父級再通過響應 子元件1 的事件去觸發子元件2的事件,這樣的鏈式操作,在子元件不多的時候,但是一個不錯的解決方法
子元件1
<template> <div> <p @click="$emit('fromFirst','來自A元件')">first元件</p> </div> </template> <script> export default { name: 'first' } </script>
子元件2
<template> 子元件2 <div>{{secondInfo}}</div> </template> <script> export default { name: 'second', data() { return { this.secondInfo: null } }, created(){ this.$on('fromFather', (info) => { this.secondInfo = info }) } } </script>
父元件
<template> <first @fromFirst='handleFromFirst' /> <second ref='second' /> </template> <script> import First from './first' import Scond from './second' export default { components: {First, Second}, data() { return { this.secondInfo: null } }, methods:{ handleFromFirst(val) { let second = this.$refs.second second.$emit('fromFather', val) } } } </script>
子元件1 觸發父元件的 fromFirst
事件, 在事件中又觸發了子元件2的 fromFather
事件,並將從子元件1 傳遞過來的引數傳遞給了該事件, 當子元件2 執行該事件的時候,將內部的 secondInfo
改變。這就實現了一個兄弟元件的互動。
這個方式在 react
裡面同樣也是適用的, 但是如果父元件內包含了多個子元件幷包含了複雜的邏輯, 有沒有更好的方式來解決這種方式呢。
大部分第一個想到的是 vuex
, 當然這在一個業務邏輯、資料複雜的專案中是一個很好的解決方法, 但是想象我們要編寫一個通用元件,這個元件可能被用到不同的專案中來, 如果使用 vuex
這就要求每一個使用這個元件的專案中都要使用 vuex
, 這顯然是不好的。
藉助中間檔案,充當中央倉庫
還好 ES6
的模組機制天然就支援建立一箇中央倉庫, 當 A 檔案使用 import value from './b.js'
來引用 B 檔案裡面的 value
的時候, 這時就會賦值給 A 檔案一個 B 檔案的 value
的 只讀引用
, 當 B 檔案裡面的 value
的值發生變化的時候, A 檔案裡面的 value
也會跟著改變。
// lib.js
export let counter = 3;
export function incCounter() {
counter++;
}
// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4
定義一個額外的例項進行一個事件的中轉,對於ES6 模組的執行機制已經有了一個講解,當模組內部發生變化的時候,引入模組的部分同樣會發生變化,當又一個額外的例項對載入機制進行引入進行on進行繫結通訊,能輕而易舉解決問題,通過b->a->c的模式直接過渡。
解決 vue 兄弟元件之間的通訊我們同樣也可以使用中央倉庫的方式來實現。
// store.js 作為中央倉庫
import Vue from 'vue'
export default new Vue()
通過 new 一個 vue 的例項當作兄弟元件互動的中央倉庫。
父級元件
<template>
<first/>
<second/>
</template>
<script>
import First from './first'
import Scond from './second'
export default {
components: {First, Second}
}
</script>
父元件只是引入子元件, 不再作為中央倉庫來過渡互動。
子元件1
<template>
<div @click='hanleClick'>子元件1</div>
</template>
<script>
import Store from './store'
export default {
name: 'first',
methods: {
handleClick() {
Store.$emit('fromFirst', '來自子元件1的傳值')
}
}
}
</script>
因為我們的目的就是把 Store
作為一箇中央倉庫,這裡我們把 fromFirst
事件新增到了 Store
上面而不是當前元件 this
上。
子元件2
<template>
子元件2
<div>{{secondInfo}}</div>
</template>
<script>
import Store from './store'
export default {
name: 'second',
data() {
return {
this.secondInfo: null
}
},
created(){
Store.$on('fromFirst', (info) => {
this.secondInfo = info
})
}
}
</script>
子元件2 裡面同樣也是使用 Store
例項來監聽 fromFirst
事件, 因為子元件1和子元件2裡面新增事件和監聽事件的是同一個例項,根據我們在上文中分析的 ES6
中的情況, 當 Store
添加了 fromFirst
這個時間之後, Store
例項的 $on
就可以監聽到這個事件並執行回撥。
跨元件深層次互動
上面講的元件之間的關係是這樣的:
我們可以實現 子元件之間的互動, 但是如果我們遇到這種情況呢? 孫元件需要跟子元件3 進行互動,還是使用上述的方法可以做到嗎? 答案是肯定的,只要能夠使用同一個中央倉庫,那麼不管什麼層級的元件複雜度,都是可以實現兩者的互動的。