Vuex以及幾種組件通訊的使用

先來看看一個簡單德例子

target.png

一個帶按鈕和計數(shù)器的簡單應用程序橙垢。按下按鈕會使計數(shù)器遞增垛叨。雖然這很容易實現(xiàn),但目標是理解基本概念柜某。

problem.dot.png

假設應用程序中有兩個組件:

1嗽元、一個按鈕(事件的來源)
2、計數(shù)器(必須根據(jù)原始事件反映更新)
這兩個組件彼此不了解喂击,無法相互通信剂癌。即使是最小的Web應用程序,這也是一種非常常見的模式翰绊。在較大的應用程序中佩谷,許多組件相互通信,并且必須相互控制监嗜。以下是基本待辦事項列表的一些交互:


todo.dot.png

這篇文章的目標

我們將探索解決同一問題的四種方法:
1谐檀、使用事件廣播在組件之間進行通信
2、使用共享狀態(tài)對象
3裁奇、使用vuex

首先桐猬,我們IncrementButton在src/components/IncrementButton.vue以下位置創(chuàng)建組件:

<template>
  <button @click.prevent="activate">+1</button>
</template>
<script>
export default {
  methods: {
    activate () {
      console.log('+1 Pressed')
    }
  }
}
</script>

<style>
</style>

接下來,我們創(chuàng)建CounterDisplay實際顯示計數(shù)器的組件框喳。讓我們創(chuàng)建一個新的基本vue組件src/components/CounterDisplay.vue

<template>
  Count is {{ count }}
</template>

<script>
export default {
  data () {
    return {
      count: 0
    }
  }
}
</script>
<style>
</style>

替換App.vue為此文件:

<template>
  <div id="app">
    <h3>Increment:</h3>
    <increment></increment>
    <h3>Counter:</h3>
    <counter></counter>
  </div>
</template>

<script>
import Counter from './components/CounterDisplay.vue'
import Increment from './components/IncrementButton.vue'
export default {
  components: {
    Counter,
    Increment
  }
}
</script>

<style>
</style>

現(xiàn)在课幕,如果npm run dev再次運行,并在瀏覽器中打開頁面五垮,您應該會看到一個按鈕和一個計數(shù)器乍惊。單擊該按鈕會在控制臺中顯示一條消息

解決方案1:事件廣播

solution1.dot.png

讓我們修改組件中的腳本。首先放仗,IncrementButton.vue我們使用$dispatch向父級發(fā)送一條消息润绎,單擊該按鈕

export default {
  methods: {
    activate () {
      // Send an event upwards to be picked up by App
      this.$dispatch('button-pressed')
    }
  }
}

在App.vue我們收聽來自孩子的事件并重新向所有孩子廣播新事件以增加。

export default {
  components: {
    Counter,
    Increment
  },
  events: {
    'button-pressed': function () {
      // Send a message to all children
      this.$broadcast('increment')
    }
  }
}
>在CounterDisplay.vue我們聽取increemnt事件并增加狀態(tài)的價值。

export default {
  data () {
    return {
      count: 0
    }
  },
  events: {
    increment () {
      this.count ++
    }
  }
}

這種方法的一些缺點:

1莉撇、對于每個操作呢蛤,父組件需要連接并將事件“分派”到正確的組件。
2棍郎、對于更大的應用程序來說其障,很難理解事件的來源。
3涂佃、業(yè)務邏輯可以在任何地方励翼,這可能使其無法維護。

解決方案2:共享狀態(tài)

讓我們回復一下我們在解決方案1中所做的一切辜荠。我們創(chuàng)建一個新文件 src/store.js

export default {
  state: {
    counter: 0
  }
}

我們先修改一下CounterDisplay.vue:

<template>
  Count is {{ sharedState.counter }}
</template>

<script>
import store from '../store'

export default {
  data () {
    return {
      sharedState: store.state
    }
  }
}
export default store
</script>

我們可以修改IncrementButton.vue

import store from '../store'

export default {
  data () {
    return {
      sharedState: store.state
    }
  },
  methods: {
    activate () {
      this.sharedState.counter += 1
    }
  }
}

解決方案3:Vuex

定義一個vuex.js文件汽抚,并在main.js里面引入

1.在main.js里面引入vuex

import Vuex from 'vuex'
import vuexs from './vuex'
Vue.use(Vuex);
const appVuex = new Vuex.Store({
    vuexs 
})
new Vue({
  el: '#app',
  router,
  appVuex ,
  components: { App },
  template: '<App/>'
})

vuex.js文件代碼如下

const state = {
 count :0
}
const mutations={
  changeMenuIndex(state, num) {
     state.count = num
  }
 }
 const actions={
    post:function(context,payload){//這里的context和我們使用的$store擁有相同的對象和方法
       return new Promise(function(resolve, reject){
         axios.post(payload.path,payload.datas).then(data=>{
            resolve(data)
         })
       });
    }
}
export default {
    state,
    mutations,
    actions
}

state里面定義自己需要的變量,這里面的變量只能通過mutations伯病,或者actions改變造烁,以下是獲取state變量方式

1、在計算屬性中返回某個狀態(tài):

<div>{{ count }}</div>
computed: {
    count () {
      return store.state.count
    }
  }

2午笛、mapState 輔助函數(shù)

import {mapState} from "vuex";
computed: {
          ...mapState(['count'])
        },

更改 Vuex 的 store 中的狀態(tài)的唯一方法是提交 mutation惭蟋。Vuex 中的 mutation 非常類似于事件:每個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數(shù) (handler)。這個回調函數(shù)就是我們實際進行狀態(tài)更改的地方季研,并且它會接受 state 作為第一個參數(shù):

const mutations={
  changeMenuIndex(state, num) {
     state.count = num
  }
 }
// 在組件中使用敞葛,num為傳過來的參數(shù)
this.$store.commit('changeMenuIndex', 10);

//這里有個問題就是怎樣傳多個參數(shù),mutations只能定義兩個參數(shù)与涡,所以這里只能以對象的形式傳值
const mutations={
  changeMenuIndex(state, payload) {
     state.count = payload.vuexNum
  }
 }
this.$store.commit('changeMenuIndex', {
   vuexNum: 10
});
//也可以這樣傳惹谐,type為函數(shù)名,其他的都是傳參
store.commit({
  type: 'changeMenuIndex',
  vuexNum: 10
})

這里可以使用 mapMutations 輔助函數(shù)將組件中的 methods 映射為 store.commit 調用

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    // mapMutations 工具函數(shù)會將 store 中的 commit 方法映射到組件的 methods 中
    ...mapMutations([
      'changeMenuIndex', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
      // `mapMutations` 也支持載荷:
      'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.commit('incrementBy', amount)`
    ]),
    ...mapMutations({
      add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
    })
  }
}

Action 類似于 mutation驼卖,不同在于:
Action 提交的是 mutation氨肌,而不是直接變更狀態(tài)。
Action 可以包含任意異步操作酌畜。

const actions={
  //寫法一
  increment (context) {
      context.commit('increment')
  }
  //寫法二
  increment ({ commit }) {
     commit('changeMenuIndex')
  }
 }
// 這里用到了對象的結構
//因為函數(shù)的參數(shù)是一個對象怎囚,函數(shù)中用的是對象中一個方法,我們可以通過對象的
//解構賦值直接獲取到該方法
//因為context本身就是一個對象桥胞,里面有state對象和commit方法例如
let context {
   state: {},
   commit: function(){}
}
//根據(jù)對象結構可以定義如下:
let {state,commit} = context
console.log(state)//state: {};
console.log(commit)//commit: function(){};
//所以放在函數(shù)里面就是
increment ({state,commit} ) {
     commit('changeMenuIndex')
  }
//具體es6的用法可以參考
`http://es6.ruanyifeng.com/`

在組件中使用this.$store.dispatch('increment ',10);,這里的傳參與上面講的一樣恳守,這些都是一些常用的東西,還有一些如getter和moudle等可以看看文檔
https://vuex.vuejs.org/zh/guide/actions.html

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末贩虾,一起剝皮案震驚了整個濱河市催烘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缎罢,老刑警劉巖伊群,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件考杉,死亡現(xiàn)場離奇詭異,居然都是意外死亡舰始,警方通過查閱死者的電腦和手機崇棠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丸卷,“玉大人枕稀,你說我怎么就攤上這事∶占担” “怎么了抽莱?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長骄恶。 經(jīng)常有香客問我,道長匕垫,這世上最難降的妖魔是什么僧鲁? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮象泵,結果婚禮上寞秃,老公的妹妹穿的比我還像新娘。我一直安慰自己偶惠,他們只是感情好春寿,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著忽孽,像睡著了一般绑改。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上兄一,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天厘线,我揣著相機與錄音,去河邊找鬼出革。 笑死造壮,一個胖子當著我的面吹牛,可吹牛的內容都是我干的骂束。 我是一名探鬼主播耳璧,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼展箱!你這毒婦竟也來了旨枯?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤析藕,失蹤者是張志新(化名)和其女友劉穎召廷,沒想到半個月后凳厢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡竞慢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年先紫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筹煮。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡遮精,死狀恐怖,靈堂內的尸體忽然破棺而出败潦,到底是詐尸還是另有隱情本冲,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布劫扒,位于F島的核電站檬洞,受9級特大地震影響,放射性物質發(fā)生泄漏沟饥。R本人自食惡果不足惜添怔,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贤旷。 院中可真熱鬧广料,春花似錦、人聲如沸幼驶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盅藻。三九已至购桑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氏淑,已是汗流浹背其兴。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夸政,地道東北人元旬。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像守问,于是被迫代替她去往敵國和親匀归。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容

  • Vuex是什么耗帕? Vuex 是一個專為 Vue.js應用程序開發(fā)的狀態(tài)管理模式穆端。它采用集中式存儲管理應用的所有組件...
    蕭玄辭閱讀 3,120評論 0 6
  • Vuex 是一個專為 Vue.js 應用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應用的所有組件的狀態(tài)仿便,并以相應...
    白水螺絲閱讀 4,668評論 7 61
  • 安裝 npm npm install vuex --save 在一個模塊化的打包系統(tǒng)中体啰,您必須顯式地通過Vue.u...
    蕭玄辭閱讀 2,938評論 0 7
  • 目錄 - 1.什么是vuex? - 2.為什么要使用Vuex? - 3.vuex的核心概念攒巍?||如何在組件中去使用...
    我跟你蔣閱讀 4,110評論 4 51
  • 作者:胡楊映月 在現(xiàn)實生活中柒莉,我們都以為婚外情所不齒,當然沽翔,我們確實也不贊同婚外情兢孝,這種行為確實與我們幾千年的情感...
    胡楊映月閱讀 1,165評論 0 2