藝術之因此存在,
就是爲了令人恢復對生活的感受,
爲了令人感覺事物,
使石頭顯出石頭的質感。
--什克洛夫斯基
複製代碼
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。javascript
Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、狀態快照導入導出等高級調試功能。html
Vuex 能夠幫助咱們管理共享狀態,並附帶了更多的概念和框架。這須要對短時間和長期效益進行權衡。vue
若是您不打算開發大型單頁應用,使用 Vuex 多是繁瑣冗餘的。確實是如此——若是您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 store 模式就足夠您所需了。可是,若是您須要構建一箇中大型單頁應用,您極可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成爲天然而然的選擇。java
總結如下,主要是如下兩點:git
主流的幾種Vue的組件間傳遞信息的方式,無非有如下幾種:ajax
經過$emit
和props
在父子組件中進行數據傳遞vuex
用eventbus
(全局事件)在中進行傳遞vue-cli
利用localstorage、sessionstorage等存儲手段來進行傳遞緩存
毫無疑問,這些個方式都能完成咱們所要的需求,可是在某種程度上面或多或少都有一些問題。例如:安全
利用$emit
和props
在兄弟關係嵌套比較深的狀況之下,代碼書寫量將會大大的增長
全局事件在使用的時候可能被被屢次觸發、銷燬時機掌握等等一系列的問題,同時做爲全局事件全部頁面都能監聽、掌控事件可能會存在安全性問題等等...
...
針對以上三種傳值方式存在各自的缺點,下面着重介紹如下主角Vuex的簡單入門。
每個 Vuex 應用的核心就是 store(倉庫)。「store」基本上就是一個容器,它包含着你的應用中大部分的狀態 (state)。Vuex 和單純的全局對象有如下兩點不一樣:
Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的組件也會相應地獲得高效更新。
你不能直接改變 store 中的狀態。改變 store 中的狀態的惟一途徑就是顯式地提交 (commit) mutation。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地瞭解咱們的應用。
上面就將vuex的四個核心選項:state mutations getters actions說了出來,下面咱們經過實例來了解這幾個概念。
新建一個.js 文件,名字位置任意,按照慣例,建議在/src/store,咱們就在該文件裏編輯代碼。
文件位置 /src/store/index.js
// 引入vue 和 vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 這裏須要use一下,固定寫法,記住便可
Vue.use(Vuex)
// 直接導出 一個 Store 的實例
export default new Vuex.Store({
// 相似 vue 的 data
state: {
name: 'oldName'
},
// 相似 vue 裏的 mothods(同步方法)
mutations: {
updateName (state) {
state.name = 'newName'
}
}
})
複製代碼
這一步其實就是新建一個store,可是咱們還沒在項目中使用。
在入口文件引入上述文件, 並稍微改一下傳給 new Vue()的參數,新增的行後面有備註。
文件位置 /src/main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store' //新增
Vue.config.productionTip = false
new Vue({
router,
store, //新增
render: h => h(App)
}).$mount('#app')
複製代碼
以上2步,若是咱們使用vue-cli腳手架建立初始化項目的時候,選擇了Vuex,以上兩步都是默認幫咱們處理好了的,使用起來很方便。
以上2步,其實已經完成了vuex的基本配置,接下來就是使用了。
文件位置 /src/App.vue
<template>
<div>
{{getName}}
<button @click="changeName" value="改名">改名</button>
</div>
</template>
<script> export default { computed:{ getName(){ return this.$store.state.name } }, methods:{ changeName () { this.$store.commit('updateName') } } } </script>
複製代碼
這裏就是一個很普通的vue文件了,有區別的地方是這裏咱們須要用computed屬性去獲取 store 裏的 "data"。
還有就是咱們要改變數據的話,再也不用 this.xxx = xxx
改爲 this.$store.commit('updateName')
。
首先是state,如何來獲取state的值呢?通常是將這個值放置在computed裏面,這樣的話一旦數據發生改變的時候,就反饋到頁面上面去。
computed:{
getName(){
return this.$store.state.name
}
},
複製代碼
state總結:用來存放組件之間共享的數據,它跟組件的data選項相似,只不過data選項是用來存放組件的私有數據。
如今假設邏輯有變,咱們最終指望獲得的數據(computed中的getName),是基於 this.$store.state.name
上通過複雜計算得來的,恰好這個getName要在好多個地方使用,那麼咱們就得複製好幾份。
vuex 給咱們提供了 getter來解決這個問題,能夠認爲是 store 的計算屬性,請看代碼:
文件位置 /src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 相似 vue 的 data
state: {
name: 'oldName'
},
// 相似 vue 的 computed -----------------如下5行爲新增
getters:{
getReverseName: state => {
return state.name.split('').reverse().join('')
}
},
// 相似 vue 裏的 mothods(同步方法)
mutations: {
updateName (state) {
state.name = 'newName'
}
}
})
複製代碼
而後咱們能夠這樣使用:
文件位置 /src/App.vue
computed:{
getName(){
return this.$store.getters.getReverseName
}
}
複製代碼
事實上, getter 不止單單起到封裝的做用,它還跟vue的computed屬性同樣,會緩存結果數據,只有當依賴改變的時候,纔要從新計算。
getter總結:getters主要是用來過濾和重組,這些事件最好也是能在計算屬性中完成,用於監聽事件變化的。
Vuex 中的 mutation 很是相似於事件:每一個 mutation 都有一個字符串的事件類型 (type) 和 一個 回調函數 (handler),且必須是同步方法。
mutation定義:
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
複製代碼
mutation使用:
this.$store.commit('increment', {
amount: 10
})
複製代碼
mutations總結:
細心的你,必定發現我以前代碼裏 mutations 頭上的註釋了 相似 vue 裏的 mothods(同步方法)。
爲何要在 methods 後面備註是同步方法呢? 由於mutation只能是同步的函數,只能是同步的函數,只能是同步的函數!!!
那麼若是咱們想觸發一個異步的操做呢?答案是: action + $dispatch, 咱們繼續修改store/index.js下面的代碼。
文件位置 /src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 相似 vue 的 data
state: {
name: 'oldName'
},
// 相似 vue 的 computed
getters:{
getReverseName: state => {
return state.name.split('').reverse().join('')
}
},
// 相似 vue 裏的 mothods(同步方法)
mutations: {
updateName (state) {
state.name = 'newName'
}
},
// 相似 vue 裏的 mothods(異步方法) -------- 如下7行爲新增
actions: {
updateNameAsync ({ commit }) {
setTimeout(() => {
commit('updateName')
}, 1000)
}
}
})
複製代碼
而後咱們能夠再咱們的vue頁面裏面這樣使用:
文件位置 /src/App.vue
methods: {
rename () {
this.$store.dispatch('updateNameAsync')
}
}
複製代碼
actions總結:
actions的做用其實和mutations是沒有差異的,無非就是一個同步、異步的差異罷了。而在功能上面主要有一下兩個區別:
actions 提交的是mutations,而不是直接變動狀態。也就是說,actions會經過mutations,讓mutations幫他提交數據的變動
actions 能夠包含任意異步操做。ajax、setTimeout、setInterval不在話下
actions第一個參數是一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit 提交一個 mutation,或者經過 context.state 和 context.getters 來獲取 state 和 getters,可是 context 對象不是 store 實例自己。下圖是我從控制檯打印出來的context對象
解釋一下這個圖:
vuex 的區域是綠色虛線框的位置
流程:
每次 vue 組件須要 給 vuex 分派 一個 actions,actions 提交一個 mutation,由 mutation 來修改 state,而後再返回給 vue 組件渲染
state 狀態只能由 mutation 來修改
actions 會能夠封裝各類 mutation 來進行修改 state
關於 state:state 就是狀態
關於 mutation:mutation 是 vuex 對 state 或者 store提交修改的惟一方式,固定方式
關於 getter:
關於 actions:
action 提交的是 mutation,而不是直接變動狀態
action 能夠包含任意異步操做
下圖是我總結的Vuex功能點思惟導圖:
參考文獻: