vue組件之間如何通訊?vue通訊的多種方式

@TOCjavascript

前言:

寫在前面: vue已經更新到V2.6.10版本(相信很快就會出3.0版本),相信咱們也遇到了須要組件之間通訊的需求,除了主流的vuex狀態管理模式,還有哪些方式解決組件之間的通訊的問題,接下來就由我一一介紹給你們;html

鎮樓圖

1、vuex狀態管理模式

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式()。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。具體介紹請轉vuexvue

其數據流向以下:

數據流向

使用:

// 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
/** * 狀態樹 */
const state = {
  count: 0
}

/** * 和組件計算屬性同樣, store 的計算屬性 * getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算 */
const getters = {
  getCount (state) {
    return state.count || 0
  }
}

/** * Vuex 中的 mutation 很是相似於事件: * 更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。 * 每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler) */
const mutations = {
  mutaCount (state, payload) {
    state.count = state.count + 1
  }

}
/** * Action 相似於 mutation,不一樣在於: * Action 提交的是 mutation,而不是直接變動狀態。 * 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,
  ...
})
複製代碼

以上已經把vuex注入到vue實例;java

組件中使用git

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

複製代碼
// src/components/vuexTwo.vue
//...
computed: {
    // ...mapGetters(['getCount']),  // 輔助函數方式使用,須要組件import {mapGetters} from 'vuex'
    // 常規方式使用
    getCount () {
      return this.$store.getters.getCount
    }
  }
//...

複製代碼

此時: 觸發vuexOne.vue的addCount時間,vuexTwo.vue的頁面能改更新;這就是vuex的簡單使用;如需瞭解 模塊module 及其餘 輔助函數 等能夠閱讀文檔vuexgithub

效果以下: vuex

vuex.gif

總結: Action和Mutation二者的功能很類似 ,而且不少時候,咱們只須要在組件中經過this.$store.commit('xxx') 或者 mapMutations輔助函數來使用 Mutation 直接更新state的數據,而不須要經過 Action 這一步,但 ActionMutation 有個很是大的區別就是: Mutation 必須是同步函數(由於mutation 中混合異步調用會致使你的程序很難調試,因此在此限制爲只能進行同步),而Action 能夠包含任意異步操做npm

2、EventBus

EventBus 的實現原理是經過一個空的vue實例做爲事件中心,經過它來觸發事件($emit) 和監聽事件($on), 巧妙而輕量地實現了任何組件間的通訊; (適合少而小的項目使用,若是有大量通訊,依舊推薦vuex)api

使用:

首先在utils建立一個新的vue實例,用做 事件中心數組

// 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組件監聽:

<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

總結: eventBus 原理 是利用一個空的vue實例當作一個事件中心,經過其分發及監聽事件來傳遞數據,也能夠實現任何組件間的通訊,包括父子、兄弟、跨級等。但當使用過多容易形成命名衝突,所以不利於大項目使用(當大項目使用時,依舊推薦vuex)


ps:以上是目前使用比較多的能夠跨組件包括兄弟組件通訊的方法,接下來說其餘有短板的方法,有興趣的能夠花幾分鐘繼續往下了解,不然客官能夠止步於此,以避免浪費您寶貴的時間 ...


3、使用最多之 props與$emit

props 由父組件A往子組件B傳遞數據,固然還能夠繼續組件B仍然能夠往C組件(A的孫組件)繼續往下傳遞,

使用 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

總結: props是單向數據流,即只能從父級傳到子級,子級改變,父級的值不會改變(用.sync修飾符修飾能夠實現雙向數據綁定),但v-model是雙向數據流,即雙向綁定,子級改變這個值時,父級也會跟着改變;$emit傳值和上面第二種的eventbus的原理一致,不過是事件分發到父級,父級能夠監聽;想了解sync修飾符請轉vue.org

4、refs  、parent、$children

ref被用來給元素或子組件註冊引用信息。引用信息將會註冊在父組件的 $refs 對象上。若是在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;若是用在子組件上,引用就指向組件

實例:

// 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調用子組件的方法,能夠把相應的數據傳導到父級;

特別地 $children拿到的當前實例的直接子組件。須要注意 $children 並不保證順序,也不是響應式的。若是你發現本身正在嘗試使用 $children 來進行數據綁定,考慮使用一個數組配合 v-for 來生成子組件,而且使用 Array 做爲真正的來源。

$parent、$children 從上述的打印,依舊能夠發現$parent、$children能拿到當前組件的父級或者子級組件實例,若是有多個,則爲數組,若是爲空,則爲空數組,若是經過這個實例去拿相應的屬性或者方法也是可行的 以下:

// 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請轉vue.org $parent請轉vue.org $children請轉vue.org

其餘

如: provide與inject

provide 和 inject (Vue2.2.0新增API) 綁定 並非可響應的。這是刻意爲之的。然而,若是你傳入了一個可監聽的對象,那麼其對象的屬性仍是可響應的。 provide與inject 轉vue.org

如: $attrs/ $listeners

$attrs/ $listeners(Vue2.4增長) 版本在普通組件中,沒有被定義爲 prop 的特性會自動添加到組件的根元素上,將已有的同名特性進行替換或與其進行智能合併 $attrs/ $listeners轉vue.org

總結:

萬能通訊: vuex、eventBus 父子通訊:$refs 、 $parent、$children、provide/inject;

本文Demo請轉 wLove-c 樓主博客請轉 王一諾

相關文章
相關標籤/搜索