先來看看一個簡單德例子
一個帶按鈕和計數(shù)器的簡單應用程序橙垢。按下按鈕會使計數(shù)器遞增垛叨。雖然這很容易實現(xiàn),但目標是理解基本概念柜某。
假設應用程序中有兩個組件:
1嗽元、一個按鈕(事件的來源)
2、計數(shù)器(必須根據(jù)原始事件反映更新)
這兩個組件彼此不了解喂击,無法相互通信剂癌。即使是最小的Web應用程序,這也是一種非常常見的模式翰绊。在較大的應用程序中佩谷,許多組件相互通信,并且必須相互控制监嗜。以下是基本待辦事項列表的一些交互:
這篇文章的目標
我們將探索解決同一問題的四種方法:
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:事件廣播
讓我們修改組件中的腳本。首先放仗,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