1. 程式人生 > >vue 解決兄弟元件、跨元件深層次的通訊問題

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 模組的執行機制已經有了一個講解,當模組內部發生變化的時候,引入模組的部分同樣會發生變化,當又一個額外的例項對載入機制進行引入進行emitemit與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 進行互動,還是使用上述的方法可以做到嗎? 答案是肯定的,只要能夠使用同一個中央倉庫,那麼不管什麼層級的元件複雜度,都是可以實現兩者的互動的。