vue組件之間如何通信乡范?vue通信的多種方式

@TOC

前言:

寫在前面: vue已經(jīng)更新到V2.6.10版本(相信很快就會出3.0版本)偎捎,相信我們也遇到了需要組件之間通信的需求,除了主流的vuex狀態(tài)管理模式讳癌,還有哪些方式解決組件之間的通信的問題穿稳,接下來就由我一一介紹給大家;

鎮(zhèn)樓圖

一晌坤、vuex狀態(tài)管理模式

Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式()逢艘。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化骤菠。具體介紹請轉(zhuǎn)vuex它改;

其數(shù)據(jù)流向如下:

數(shù)據(jù)流向

使用:

// cdn
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

// npm 
npm install vuex --save

//yarn 
yarn add vuex

  • 使用
//  /src/store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
//  /src/store.js
/**
 * 狀態(tài)樹
 */
const state = {
  count: 0
}

/**
 * 和組件計算屬性一樣, store 的計算屬性
 * getter 的返回值會根據(jù)它的依賴被緩存起來商乎,且只有當(dāng)它的依賴值發(fā)生了改變才會被重新計算
 */
const getters = {
  getCount (state) {
    return state.count || 0
  }
}

/**
 * Vuex 中的 mutation 非常類似于事件:
 * 更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation央拖。
 * 每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調(diào)函數(shù) (handler)
 */
const mutations = {
  mutaCount (state, payload) {
    state.count = state.count + 1
  }

}
/**
 * Action 類似于 mutation,不同在于:
 * Action 提交的是 mutation鹉戚,而不是直接變更狀態(tài)鲜戒。
 * Action 可以包含任意異步操作。
 */
const actions = {
  actCount ({commit}, payload) {
    commit('mutaCount', payload)
  }
}

const store = new Vuex.Store(
  {
    state,
    getters,
    mutations,
    actions
  }
)

export default store
// src/main.js
...
import store from './store'


/* eslint-disable no-new */
new Vue({
  ...
  store,
  ...
})

以上已經(jīng)把vuex注入到vue實(shí)例抹凳;

組件中使用

// src/components/vuexOne.vue
//...
methods: {
    // ...mapActions(['actCount']), // 輔助函數(shù)方式使用遏餐,需要組件import {mapActions} from 'vuex'
    addCount () {
      // this.actCount()
      this.$store.dispatch('actCount')
    }
  }
//...

// src/components/vuexTwo.vue
//...
computed: {
    // ...mapGetters(['getCount']),  // 輔助函數(shù)方式使用,需要組件import {mapGetters} from 'vuex'
    // 常規(guī)方式使用
    getCount () {
      return this.$store.getters.getCount
    }
  }
//...

此時: 觸發(fā)vuexOne.vue的addCount時間赢底,vuexTwo.vue的頁面能改更新失都;這就是vuex的簡單使用;如需了解 模塊module 及其他 輔助函數(shù) 等可以閱讀文檔vuex

效果如下:


vuex.gif

總結(jié): Action和Mutation兩者的功能很相似 幸冻,并且很多時候粹庞,我們只需要在組件中通過this.$store.commit('xxx') 或者 mapMutations輔助函數(shù)來使用 Mutation 直接更新state的數(shù)據(jù),而不需要通過 Action 這一步洽损,但 ActionMutation 有個非常大的區(qū)別就是: Mutation 必須是同步函數(shù)(因?yàn)閙utation 中混合異步調(diào)用會導(dǎo)致你的程序很難調(diào)試庞溜,所以在此限制為只能進(jìn)行同步),而Action 可以包含任意異步操作 趁啸。

二强缘、EventBus

EventBus 的實(shí)現(xiàn)原理是通過一個空的vue實(shí)例作為事件中心督惰,通過它來觸發(fā)事件($emit) 和監(jiān)聽事件($on), 巧妙而輕量地實(shí)現(xiàn)了任何組件間的通信; (適合少而小的項(xiàng)目使用不傅,如果有大量通信,依舊推薦vuex)

使用:

首先在utils創(chuàng)建一個新的vue實(shí)例赏胚,用作 事件中心

// utils/eventbus.js
...
import Vue from 'vue'

export default new Vue({
  name: 'EventBus'
})

eventBusOne組件引入:

<template>
  <div class="eventBusOne">
    <div class="add-count-button-box">
      <div>我是eventBusOne組件:</div>
      <div class="add-count-button" @click="addCount">state++</div>
    </div>
  </div>
</template>
<script>
import eventBus from '../../../utils/eventBus'
export default {
  name: 'EventBusOne',
  data () {
    return {
      count: 1
    }
  },
  methods: {
    addCount () {
      this.count += 1
      eventBus.$emit('data-count', this.count)
    }
  }
}
</script>

eventBusTwo組件監(jiān)聽:

<template>
  <div class="eventBusTwo">
    <div class="add-count-button-box">
      <div>我是eventBusTwo組件:</div>
      <div>{{count}}</div>
    </div>

  </div>
</template>

<script>
import eventBus from '../../../utils/eventBus'
export default {
  name: 'EventBusTwo',
  data () {
    return {
      count: 1
    }
  },
  computed: {

  },
  mounted () {
    eventBus.$on('data-count', data => {
      this.count = data
    })
  }
}
</script>

效果如下:

eventBus.gif

總結(jié): eventBus 原理 是利用一個空的vue實(shí)例當(dāng)做一個事件中心访娶,通過其分發(fā)及監(jiān)聽事件來傳遞數(shù)據(jù),也可以實(shí)現(xiàn)任何組件間的通信觉阅,包括父子崖疤、兄弟秘车、跨級等。但當(dāng)使用過多容易造成命名沖突劫哼,因此不利于大項(xiàng)目使用(當(dāng)大項(xiàng)目使用時叮趴,依舊推薦vuex)


ps:以上是目前使用比較多的可以跨組件包括兄弟組件通信的方法,接下來講其他有短板的方法权烧,有興趣的可以花幾分鐘繼續(xù)往下了解眯亦,否則客官可以止步于此,以免浪費(fèi)您寶貴的時間 ...


三般码、使用最多之 props與$emit

props 由父組件A往子組件B傳遞數(shù)據(jù)妻率,當(dāng)然還可以繼續(xù)組件B仍然可以往C組件(A的孫組件)繼續(xù)往下傳遞,

使用 propsOne(父組件)

<template>
<div class="propsOne">
    <div class="add-count-button-box">
      <div>我是propsOne組件:</div>
      <div class="add-count-button" @click="addCount">count++</div>
      <div class="add-count-button" @click="addState">state++</div>
    </div>
  <propsTwo v-model="count" :state="state" @addCount="twoAddCount" @addState="twoAddState"></propsTwo>
</div>
</template>

<script>
import propsTwo from './propsTwo'
export default {
  name: 'PropsOne',
  components: {
    propsTwo
  },
  data () {
    return {
      count: 1,
      state: 1
    }
  },
  methods: {
    addCount () {
      this.count += 1
    },
    addState () {
      this.state += 1
    },
    twoAddCount (value) {
      this.count = value
    },
    twoAddState (value) {
      this.state = value
    }
  }
}

</script>

使用 propsTwo(子組件)

<template>
<div class="propsTwo">
  <div>count:{{value}}</div>
  <div class="state">state:{{state}}</div>
  <div>我是 propsTwo組件: </div>
  <div class="add-count-button" @click="addCount">count++</div>
  <div class="add-count-button" @click="addState">state++</div>
</div>
</template>

<script>
export default {
  name: 'PropsTwo',
  props: {
    value: {
      type: Number,
      default: 1
    },
    state: {
      type: Number,
      default: 1
    }
  },
  data () {
    return {
    }
  },
  methods: {
    addCount () {
      let count = this.value
      count++
      this.$emit('addCount', count)
    },
    addState () {
      let state = this.state
      state++
      this.$emit('addState', state)
    }
  }
}
</script>

效果如下:

props.gif

總結(jié): props是單向數(shù)據(jù)流板祝,即只能從父級傳到子級宫静,子級改變,父級的值不會改變(用.sync修飾符修飾可以實(shí)現(xiàn)雙向數(shù)據(jù)綁定)券时,但v-model是雙向數(shù)據(jù)流孤里,即雙向綁定,子級改變這個值時革为,父級也會跟著改變扭粱;$emit傳值和上面第二種的eventbus的原理一致,不過是事件分發(fā)到父級震檩,父級可以監(jiān)聽琢蛤;想了解sync修飾符請轉(zhuǎn)vue.org

四、refs 抛虏、parent博其、$children

ref被用來給元素或子組件注冊引用信息。引用信息將會注冊在父組件的 $refs 對象上迂猴。如果在普通的 DOM 元素上使用慕淡,引用指向的就是 DOM 元素;如果用在子組件上沸毁,引用就指向組件

實(shí)例:

// ref.vue
<template>
<div class="ref">
 <div class="add-count-button" @click="getCount">
     獲取refTwo的count峰髓,其值為:{{count}}
  </div>
  <refOne ref="refOne"></refOne>

</div>
</template>

<script>
import refOne from '../components/refDemo/refOne'
export default {
  name: 'Props',
  components: {
    refOne
  },
  data () {
    return {
      count: ''
    }
  },
  methods: {
    getCount () {
      console.log('ref========', this.$parent) // Vue
      console.log('ref========', this.$children) // refOne
      this.count = this.$refs.refOne.getCount()
    }
  }
}
</script>
// refOne
<template>
  <div class="refOne">
    <refTwo ref="refTwo"></refTwo>
    <refTwo></refTwo>
  </div>
</template>

<script>
import refTwo from './refTwo'
export default {
  name: 'RefOne',
  components: {
    refTwo
  },
  data () {
    return {
      count: 2
    }
  },
  methods: {
    getCount () {
      console.log('refOne========', this.$parent) // refOne
      console.log('refOne========', this.$children) // [refTwo,refTwo]
      return this.$refs.refTwo.getCount()
    }
  }
}
</script>
// refTwo
<template>
  <div class="refTwo">
    <div class="add-count-button-box">
      <div>我是refTwo組件的count ==== {{count}}</div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'RefTwo',
  data () {
    return {
      count: 1000
    }
  },
  methods: {
    getCount () {
      console.log('refTwo========', this.$parent) // refOne
      console.log('refTwo========', this.$children) // []
      return this.count
    }
  }
}
</script>

從上面的操作可知,通過ref調(diào)用子組件的方法息尺,可以把相應(yīng)的數(shù)據(jù)傳導(dǎo)到父級携兵;

特別地 $children拿到的當(dāng)前實(shí)例的直接子組件。需要注意 $children 并不保證順序搂誉,也不是響應(yīng)式的徐紧。如果你發(fā)現(xiàn)自己正在嘗試使用 $children 來進(jìn)行數(shù)據(jù)綁定,考慮使用一個數(shù)組配合 v-for 來生成子組件,并且使用 Array 作為真正的來源并级。

$parent拂檩、$children 從上述的打印,依舊可以發(fā)現(xiàn)$parent嘲碧、$children能拿到當(dāng)前組件的父級或者子級組件實(shí)例稻励,如果有多個,則為數(shù)組愈涩,如果為空钉迷,則為空數(shù)組,如果通過這個實(shí)例去拿相應(yīng)的屬性或者方法也是可行的 如下:

// ref
methods: {
    getCount () {
      console.log('ref========', this.$parent) // Vue
      console.log('ref========', this.$children) // refOne
      this.count = this.$refs.refOne.count  // count 為 refOne的data里面的count ===2
    }
  }

ref請轉(zhuǎn)vue.org
$parent請轉(zhuǎn)vue.org
$children請轉(zhuǎn)vue.org

其他

如: provide與inject

provide 和 inject (Vue2.2.0新增API) 綁定 并不是可響應(yīng)的钠署。這是刻意為之的糠聪。然而,如果你傳入了一個可監(jiān)聽的對象谐鼎,那么其對象的屬性還是可響應(yīng)的舰蟆。
provide與inject 轉(zhuǎn)vue.org

如: $attrs/ $listeners

$attrs/ $listeners(Vue2.4增加) 版本在普通組件中,沒有被定義為 prop 的特性會自動添加到組件的根元素上狸棍,將已有的同名特性進(jìn)行替換或與其進(jìn)行智能合并身害。
$attrs/ $listeners轉(zhuǎn)vue.org

總結(jié):

萬能通信: vuex、eventBus
父子通信:$refs 草戈、 $parent塌鸯、$children、provide/inject唐片;

本文Demo請轉(zhuǎn) wLove-c
樓主博客請轉(zhuǎn) 王一諾

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丙猬,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子费韭,更是在濱河造成了極大的恐慌茧球,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件星持,死亡現(xiàn)場離奇詭異抢埋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)督暂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門揪垄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人逻翁,你說我怎么就攤上這事饥努。” “怎么了卢未?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵肪凛,是天一觀的道長。 經(jīng)常有香客問我辽社,道長伟墙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任滴铅,我火速辦了婚禮戳葵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘汉匙。我一直安慰自己拱烁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布噩翠。 她就那樣靜靜地躺著戏自,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伤锚。 梳的紋絲不亂的頭發(fā)上擅笔,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機(jī)與錄音屯援,去河邊找鬼猛们。 笑死,一個胖子當(dāng)著我的面吹牛狞洋,可吹牛的內(nèi)容都是我干的弯淘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼吉懊,長吁一口氣:“原來是場噩夢啊……” “哼庐橙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起借嗽,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤怕午,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后淹魄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體郁惜,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年甲锡,在試婚紗的時候發(fā)現(xiàn)自己被綠了兆蕉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡缤沦,死狀恐怖虎韵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缸废,我是刑警寧澤包蓝,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布驶社,位于F島的核電站,受9級特大地震影響测萎,放射性物質(zhì)發(fā)生泄漏亡电。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一硅瞧、第九天 我趴在偏房一處隱蔽的房頂上張望份乒。 院中可真熱鬧,春花似錦腕唧、人聲如沸或辖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽颂暇。三九已至,卻和暖如春但惶,著一層夾襖步出監(jiān)牢的瞬間蟀架,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工榆骚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留片拍,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓妓肢,卻偏偏與公主長得像捌省,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子碉钠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • vue是數(shù)據(jù)驅(qū)動視圖更新的框架, 所以對于vue來說組件間的數(shù)據(jù)通信非常重要纲缓,那么組件之間如何進(jìn)行數(shù)據(jù)通信的呢?首...
    云翼飛閱讀 545評論 0 0
  • 原文地址 vue是數(shù)據(jù)驅(qū)動視圖更新的框架, 所以對于vue來說組件間的數(shù)據(jù)通信非常重要喊废,那么組件之間如何進(jìn)行數(shù)據(jù)通...
    lovelydong閱讀 391評論 0 0
  • 前言 組件是 vue.js最強(qiáng)大的功能之一祝高,而組件實(shí)例的作用域是相互獨(dú)立的,這就意味著不同組件之間的數(shù)據(jù)無法相互引...
    用技術(shù)改變世界閱讀 2,154評論 1 3
  • 摘要: 總有一款合適的通信方式污筷。 作者:浪里行舟 Fundebug經(jīng)授權(quán)轉(zhuǎn)載工闺,版權(quán)歸原作者所有。 前言 組件是 v...
    Fundebug閱讀 15,573評論 3 57
  • (攝于威尼斯) 回憶 是一條靜靜流淌的河 懷念堆積成 通向過往的橋 歷經(jīng)千回百轉(zhuǎn) 終至彼岸 卻發(fā)現(xiàn) 你抵達(dá)的不過是...
    米M妮閱讀 943評論 12 43