Vue 組件間通信方法匯總

除了使用 Vuex 方法外,vue 提供了各種各樣的組件間通信的方案。文章整理一下父子組件、兄弟組件、祖先后代組件間是如何通信的。 ??

?? 父子組件通信

props 和 $emit 父子組件通信

子組件有時(shí)需要與父組件進(jìn)行溝通,溝通的方式就是子組件 emit 事件,父組件通過(guò)監(jiān)聽(tīng)這個(gè)事件來(lái)做進(jìn)一步動(dòng)作。而父組件與子組件通信則使用 props

假設(shè)這里有一個(gè)父組件并引入了一個(gè)子組件 my-comp:

<my-comp v-for="msg in msgs" :key="msg.id" :msg="msg"></my-comp>

父組件有一系列 msg 數(shù)據(jù)需要通過(guò)子組件渲染,將 msg 作為 prop 傳遞給子組件即可:

import MyComp from '@/components/MyComp.vue'

export default {
  name: 'home',
  components: {
    MyComp
  },
  data () {
    return {
      msgs: [{
        id: 1, data: 'hello js'
      }, {
        id: 2, data: 'css world'
      }, {
        id: 3, data: 'animated style'
      }]
    }
  }
}

我們通過(guò)點(diǎn)擊子組件每一項(xiàng)觸發(fā)一個(gè)事件,父組件監(jiān)聽(tīng)這個(gè)事件去動(dòng)態(tài)改變子組件的 color 樣式,這就是父組件監(jiān)聽(tīng)子組件事件,事件處理函數(shù)可以從子組件傳遞值給父組件:

<my-comp v-for="msg in msgs" :key="msg.id" :msg="msg" :colored="colored" @handle-change-color="handleChangeColor"></my-comp>

首先增加一個(gè)事件 handle-change-color 當(dāng)這個(gè)事件被觸發(fā)時(shí)修改名為 color 的 data,然后將 colored 通過(guò) props 傳入到子組件:

import MyComp from '@/components/MyComp.vue'

export default {
  name: 'home',
  components: { // 注冊(cè)組件
    MyComp
  },
  data () {
    return {
      colored: false, // 狀態(tài)
      msgs: [{
        id: 1, data: 'hello js'
      }, {
        id: 2, data: 'css world'
      }, {
        id: 3, data: 'animated style'
      }]
    }
  },
  methods: {
    handleChangeColor () {
      this.colored = !this.colored // 監(jiān)聽(tīng)事件動(dòng)態(tài)改變 colored
    }
    // handleChangeColor (param) { // 子組件觸發(fā)的事件可能包含參數(shù)
  }
}

然后編輯子組件:

<div>
    <div @click="handleClick" :style="{color}">
        {{msg.id}} - {{msg.data}} ?
    </div>
</div>

首先渲染數(shù)據(jù),并監(jiān)聽(tīng) click 點(diǎn)擊事件,當(dāng)點(diǎn)擊觸發(fā)事件處理函數(shù) handleClick

export default {
  name: 'MyComp',
  computed: {
    color () { // color 為樣式
      return this.colored ? 'red' : 'black' // 根據(jù)父組件傳入的 props 動(dòng)態(tài)修改樣式
    }
  },
  props: ['msg', 'colored'],
  methods: {
    handleClick (e) {
      this.$emit('handle-change-color') // 使用 $emit 方法觸發(fā)父組件 handle-change-color 事件
    //   this.$emit('handler', 'param') // 還可以給事件傳遞參數(shù)
    }
  }
}

子組件接收 colored 父組件傳遞來(lái)的 prop,返回一個(gè)計(jì)算后的屬性 color,根據(jù) colored 返回不同樣式。handleClick 處理當(dāng)子組件元素被點(diǎn)擊時(shí) $emit 派發(fā)父組件的 handle-change-color 事件

效果如下:

[圖片上傳失敗...(image-a68723-1555665093712)]

父組件 $children 操作子組件

使用 $children 操作子組件。如上述例子中,colored 被定義在父組件中,可以將其移動(dòng)到子組件中,并在父組件通過(guò) $children 訪問(wèn)到子組件:

<template>
  <div @click="handleClick" class="home">
    <my-comp v-for="msg in msgs" :key="msg.id" :msg="msg"></my-comp>
  </div>
</template>

handleClick 事件被放置在 div 中

import MyComp from '@/components/MyComp.vue'

export default {
  // ...
  data () {
    return {
      msgs: [{
          // ...
      }]
    }
  },
  methods: {
    handleClick () {
      this.$children.forEach(child => {
        child.$data.colored = !child.$data.colored // 逐一控制子組件的 $data
      })
    }
  }
}

在子組件中不需要 $emit 事件,只需維護(hù)一個(gè) data:

export default {
  name: 'MyComp',
  data () {
    return {
      colored: false // colored 狀態(tài)
    }
  },
  computed: {
    color () {
      return this.colored ? 'red' : 'black'
    }
  },
  props: ['msg']
}

子組件 $parent 訪問(wèn)父組件

子組件可通過(guò) $parent 來(lái)修改父組件的 $data,因此 colored 定義在父組件中。

<template>
  <div class="home">
    <my-comp v-for="msg in msgs" :key="msg.id" :msg="msg" :colored="colored"></my-comp>
  </div>
</template>

通過(guò) prop 傳遞 colored 參數(shù)給子組件

import MyComp from '@/components/MyComp.vue'

export default {
  name: 'home',
  components: {
    MyComp
  },
  data () {
    return {
      colored: false, // 父組件維護(hù)一個(gè) colored 狀態(tài)
      msgs: [{
          // ...
      }]
    }
  }
}

父組件定義 colored 狀態(tài)

<template>
  <div>
    <div @click="handleClick" :style="{color}">
      {{msg.id}} - {{msg.data}} ?
    </div>
  </div>
</template>

子組件渲染 msg 并監(jiān)聽(tīng) click 事件

export default {
    // ...
  props: ['msg', 'colored'],
  methods: {
    handleClick (e) {
      this.$parent.$data.colored = !this.$parent.$data.colored
    }
  }
}

通過(guò) $parent 訪問(wèn)父組件,并修改 $data 狀態(tài)

?? 非父子組件通信

中央事件總線

我們可以使用使用中央事件總線來(lái)處理非父子組件間的通信

具體步驟是創(chuàng)建一個(gè) Vue 實(shí)例,然后 $on 監(jiān)聽(tīng)事件,$emit 來(lái)派發(fā)事件

// src/eventBus.js

import Vue from 'vue'
export default new Vue()

首先創(chuàng)建并導(dǎo)出一個(gè) Vue 實(shí)例

import bus from '@/eventbus'

export default {
    // ...
  methods: {
    handleClick (e) {
      bus.$emit('change-color')
    }
  }
}

后代元素 $emit 觸發(fā) eventBus 的事件

import bus from '@/eventbus'

export default {
    // ...
  mounted () {
    bus.$on('change-color', () => {
      this.colored = !this.colored
    })
  }
}

祖先元素 $on 方法監(jiān)聽(tīng) eventBus 的事件

provide/inject

適用于祖先和后代關(guān)系的組件間的通信,祖先元素通過(guò) provide 提供一個(gè)值,后代元素則通過(guò) inject 獲取到這個(gè)值。這個(gè)值默認(rèn)是非響應(yīng)的,如果是對(duì)象那么則是響應(yīng)式的:

export default {
  name: 'home',
  provide () {
    return {
      colored: this.colored // 依賴(lài)于 data
    }
  },
  components: {
    MyComp
  },
  data () {
    return {
      colored: { // 必須為對(duì)象
        value: false
      },
      msgs: [{
// ... 

首先通過(guò) provide 對(duì)外提供一個(gè) colored,這個(gè)屬性依賴(lài)于 data 中的 colored,該變量必須為一個(gè)對(duì)象,才是響應(yīng)式的。

?? 必須為一個(gè)對(duì)象

  methods: {
    handleChangeColor () {
      this.colored.value = !this.colored.value
    }
  }

祖先組件監(jiān)聽(tīng)事件或其他途徑去修改 data 改變狀態(tài)。

export default {
  name: 'MyComp',
  inject: ['colored'], // inject colored
  computed: {
    color () {
      return this.colored.value ? 'red' : 'black' // do more...
    }
  },
// ...

后代組件通過(guò) inject 獲取到祖先組件提供的對(duì)象,根據(jù)對(duì)象做進(jìn)一步動(dòng)作。

$root 直接訪問(wèn)根組件

根據(jù)官方的文檔,我們可以通過(guò) $root 來(lái)直接訪問(wèn)到 Vue 實(shí)例

比方說(shuō)將數(shù)據(jù)存儲(chǔ)在 Vue 實(shí)例中:

// src/main.js

new Vue({
  data () {
    return { // 在這里??!
      colored: false
    }
  },
  router,
  store,
  render: h => h(App)
}).$mount('#app')

然后我們?cè)谄渌鱾€(gè)組件中都能夠使用:

export default {
  name: 'MyComp',
  // ...
  mounted () {
    console.log(this.$root) // 直接訪問(wèn)到根組件
  },
  // ...
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 您將在本文當(dāng)中了解到,往網(wǎng)頁(yè)中添加數(shù)據(jù),從傳統(tǒng)的dom操作過(guò)渡到數(shù)據(jù)層操作,實(shí)現(xiàn)同一個(gè)目標(biāo),兩種不同的方式....
    itclanCoder閱讀 26,244評(píng)論 1 12
  • 組件(Component)是Vue.js最核心的功能,也是整個(gè)架構(gòu)設(shè)計(jì)最精彩的地方,當(dāng)然也是最難掌握的。...
    六個(gè)周閱讀 5,770評(píng)論 0 32
  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對(duì)于 Vue 1.0 印象不深的內(nèi)容。關(guān)于...
    云之外閱讀 5,177評(píng)論 0 29
  • 什么是組件? 組件 (Component) 是 Vue.js 最強(qiáng)大的功能之一。組件可以擴(kuò)展 HTML 元素,封裝...
    youins閱讀 9,708評(píng)論 0 13
  • Vue組件之間通信的七種方式 使用Vue也有很長(zhǎng)一段時(shí)間,但是一直以來(lái)都沒(méi)對(duì)其組件之間的通信做一個(gè)總結(jié),這次就借此...
    豆豆_4edc閱讀 671評(píng)論 0 2

友情鏈接更多精彩內(nèi)容