原文
簡書原文:https://www.jianshu.com/p/0546983f5997
大綱
1、什么是Vuex
2、什么是“狀態管理模式”?
3、什么情況下應該使用 Vuex?
4、Vuex和全局變量的概念區別
5、最簡單的store
6、Vuex的簡單使用
6.1、vue文件版本
6.2、js文件版本
1、什么是Vuex
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式。它采用集中式存儲管理應用的所有組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、狀態快照導入導出等高級調試功能。
2、什么是“狀態管理模式”?
讓我們從一個簡單的 Vue 計數應用開始:
new Vue({
// state
data () {
return {
count: 0
}
},
// view
template: `
<div>{{ count }}</div>
`,
// actions
methods: {
increment () {
this.count++
}
}
})
這個狀態自管理應用包含以下幾個部分:
1、state,驅動應用的數據源;
2、view,以聲明方式將 state 映射到視圖;
3、actions,響應在 view 上的用戶輸入導致的狀態變化。
以下是一個表示“單向數據流”理念的極簡示意:

問題暴露
但是,當我們的應用遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞:
1、多個視圖依賴於同一狀態。
2、來自不同視圖的行為需要變更同一狀態。
對於問題一,傳參的方法對於多層嵌套的組件將會非常繁瑣,並且對於兄弟組件間的狀態傳遞無能為力。對於問題二,我們經常會采用父子組件直接引用或者通過事件來變更和同步狀態的多份拷貝。以上的這些模式非常脆弱,通常會導致無法維護的代碼。
解決方式
因此,我們為什么不把組件的共享狀態抽取出來,以一個全局單例模式管理呢?在這種模式下,我們的組件樹構成了一個巨大的“視圖”,不管在樹的哪個位置,任何組件都能獲取狀態或者觸發行為!
另外,通過定義和隔離狀態管理中的各種概念並強制遵守一定的規則,我們的代碼將會變得更結構化且易維護。
這就是 Vuex 背后的基本思想,借鑒了 Flux、Redux、和 The Elm Architecture。與其他模式不同的是,Vuex 是專門為 Vue.js 設計的狀態管理庫,以利用 Vue.js 的細粒度數據響應機制來進行高效的狀態更新。

3、什么情況下應該使用 Vuex?
雖然 Vuex 可以幫助我們管理共享狀態,但也附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。
如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗余的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 global event bus 就足夠您所需了。但是,如果您需要構建一個中大型單頁應用,您很可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成為自然而然的選擇。
4、Vuex和全局變量的概念區別
每一個 Vuex 應用的核心就是 store(倉庫)。“store”基本上就是一個容器,它包含着你的應用中大部分的狀態 (state)。Vuex 和單純的全局對象有以下兩點不同:
1、Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那么相應的組件也會相應地得到高效更新。
2、你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地了解我們的應用。
5、最簡單的store
/*
安裝 Vuex 之后,讓我們來創建一個 store。創建過程直截了當——僅需要提供一個初始
state 對象和一些 mutation:
*/
// 如果在模塊化構建系統中,請確保在開頭調用了 Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
/*
現在,你可以通過 store.state 來獲取狀態對象,以及通過 store.commit 方法觸發
狀態變更:
*/
store.commit('increment')
console.log(store.state.count) // -> 1
/*
再次強調,我們通過提交 mutation 的方式,而非直接改變 store.state.count,是因
為我們想要更明確地追蹤到狀態的變化。這個簡單的約定能夠讓你的意圖更加明顯,這樣你
在閱讀代碼的時候能更容易地解讀應用內部的狀態改變。此外,這樣也讓我們有機會去實現一
些能記錄每次狀態改變,保存狀態快照的調試工具。有了它,我們甚至可以實現如時間穿梭般
的調試體驗。
由於 store 中的狀態是響應式的,在組件中調用 store 中的狀態簡單到僅需要在計算
屬性中返回即可。觸發變化也僅僅是在組件的 methods 中提交 mutation。
*/
6、Vuex的簡單使用
下載Vuex
vue-cli搭建的項目 利用腳手架搭建項目之后,可以通過npm引入vuex npm install vuex
也可以直接通過引入文件
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>
實例:基本的Vuex計數應用
vue文件版本
1、創建store狀態管理
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 狀態
const state = {
count: 0
}
const mutations = {
INCREMENT (state) {
state.count++
},
DECREMENT (state) {
state.count--
}
}
const actions = {
increment: ({ commit }) => commit('INCREMENT'),
decrement: ({ commit }) => commit('DECREMENT')
}
const getters = {
moreCount: function () {
return state.count + 'more'
}
}
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
2、引入store狀態管理
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false
new Vue({
el: '#app',
store,
components: { App },
template: '<App/>'
})
3、使用store進行狀態管理——計數
3.1、相應點擊事件發布(dispatch)狀態
<template>
<div>
<div>{{ msg }}</div><br>
<div>
<button @click="increment()">+</button>
<button @click="decrement()">-</button>
</div><br>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'HelloWorld'
}
},
methods: {
increment () {
console.log('+++')
this.$store.dispatch('increment')
},
decrement () {
console.log('---')
this.$store.dispatch('decrement')
}
}
}
</script>
<style scoped>
</style>
3.2、接收狀態改變之后的值
<template>
<div>
{{ msg }}<br>
{{ count }}<br>
{{ moreCount }}
</div>
</template>
<script>
export default {
name: 'SimpleCounter',
data () {
return {
msg: 'SimpleCounter'
}
},
computed: {
count () {
return this.$store.state.count
},
moreCount () {
return this.$store.getters.moreCount
}
}
}
</script>
<style scoped>
</style>
js文件版本
<html>
<meta charset="utf-8">
<head>
<title>Test</title>
</head>
<body>
<div id="app">
<p>{{ count }}</p>
<p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</p>
</div>
<script src="./vue.js"></script>
<script src="./vuex.js"></script>
<script src="./vuex-demo2.js"></script>
</body>
</html>
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
})
new Vue({
el: '#app',
computed: {
count () {
return store.state.count
}
},
methods: {
increment () {
store.commit('increment')
},
decrement () {
store.commit('decrement')
}
}
})
