前言
承接上文vue2.0一起在懵逼的海洋里越陷越深(三)
前面一篇講了vue-router的router-link
,
有讀者說希望能先看到vuex的文章
其實vuex在我的vue2.0的demo里已經在使用了
想想確實應該先來點vuex的了,因為有些有關的狀態管理急需vuex的加入
好,那么這次就先上vuex吧!
正文
OK!先介紹下vuex
vuex是vuejs的狀態管理方案
因為vuex有些復雜,一般應用在較復雜的狀態環境下,如果是比較簡單的應用就不需要安裝vuex了
vuex單向數據流
如上圖所示是vuex單向數據流的流程
** 我知道,如果是第一次接觸這玩意,到這就懵逼了,就像我第一次看文檔一樣 **
** 下面解釋下State
**
前面說了vuex是vuejs的狀態管理方案,這里的狀態就是圖中的state
在平時寫寫前端的過程中,都會涉及到狀態的問題,
比如你看到了一篇文章寫的不錯,就想要收藏,
然后又對作者有些興趣,于是又加了關注,當然這些最后都是需要前端來表達出來
這里面就涉及了兩個狀態就是收藏與關注
這里的收藏與關注我們可以將其用一個變量來表示,當然如這兩種只存在兩個相對狀態的用布爾值(bool
)來表示就可以了
** 然后是view
**
view
就是視圖,也就是前端所寫的頁面,前面的state
就可以在view
里面得到體現,即是你看到的是否關注了作者
** 而后是Actions
**
Actions
是View
用來改變State
的方法,通過改變State
從而改變View
的顯示
這么說有些抽象,打個比方
假設學生小明生病了
小明要向班主任請假(小明就是View
,小明想改變自己的顯示狀態,從上學狀態變成請假狀態)
于是小明口頭向班主任請假(請假就是Actions
,小明通過請假這一個方法達到請假的目的)
班主任批準,小明請假成功(班主任就是State
的提供者,小明通過請假方法使班主任改變小明的State
狀態)
著也就解釋了為什么要有這個流程,有了這個流程就可以統一管理各個view
的各個狀態
vuex多個組件共享狀態
先貼個流程圖,懵逼是沒啥關系的
可以看到這一張圖比前面一張復雜了許多,其實里面的實線框就是上圖的升級版
情況是這樣,原來小明學校里這段時間許多同學得了流感,于是同學們一窩蜂的要求請假,
學校里因為人太多,又沒有一個記錄,人數清點不過來了,于是班主任要求請假必須提交請假條
好的,來解釋下上圖內的實線部分,之前的View
在這里改名成了Vue Components
,代表了多個組件(這里即是指多個同學)
包括小明在內的多個同學Vue Components
都得了流感,一起想要請假Actions
(他們即將共享一個請假狀態),小明代表多個同學寫了一張請假條交給班主任(State
提供者)簽字同意(簽字同意這個動作就是Mutations
,觸發了State
的改變),班主任同意后統一給他們改變了State
(請假成功)
這里的多了一個同步與異步的區別,其中Mutations
只受理同步處理,而Actions
就是執行異步操作的函數,作為代價,Actions
不再能直接觸發改變State
狀態,而是需通過Mutations
來觸發State
的改變
情況是這樣,因為不只是一個班的學生得了流感,請假的人比較多,學校Backend API
需要做一個統計,于是請假需要得到學校專門的請假條的并通過學校簽字才能生效,這里就有了虛線部分。
請假Actions
改變State
的方法不再是僅僅班主任簽字就可以了,而是需要通過學校這個前提,于是Actions
就變成了一個異步請求,需要得到學校Backend API
的專門的請假條和簽字同意后,才能向班主任提交改變State
的申請
這里想要表達的意思就是,Vue Components
改變自身狀態需要通過Actions
(有需要的話要向后端接口Backend API
發送請求)來操作Mutations
改變State
從而改變自身狀態。
至于圖中沒有說到的Devtools
是一個開發者工具,是一個便于查看和管理vue應用以及vuex狀態的瀏覽器插件。
你可以在里面看到你vue對象和vuex每一次的commit,commit后面會說到。還有你當前的應用狀態
附上一個devtools庫地址
架構vuex
項目結構:
├── main.js
├── App.vue
├── components
│ ├── Home.vue
│ └── ...
└── store
├── index.js # 組裝模塊并導出 store 的地方
├── actions.js # 根級別的 action
├── mutations.js # 根級別的 mutation
├── types.js # mutation命名空間
└── modules
├── demo.js # demo模塊
└── status.js # 全局應用狀態模塊
結構可以根據個人需要進行調整
** 下面開始構建store/index.js
**
當然在這之前,如果沒有安裝vuex的需要先安裝
npm i vuex -S
由于vuex的內容太多,這里先說基礎用法
首先為store/index.js
編寫內容
import Vue from 'vue'
// 導入vue
import Vuex from 'vuex'
// 導入vuex
import status from './modules/status'
// 導入status模塊(這是我管理全局應用狀態的模塊)
import demo from './modules/demo'
// 導入demo模塊(這個的部分演示可以在http://vue2.leenty.com/demo/vuex_state/里看到)
Vue.use(Vuex)
// 告訴vue將要使用vuex
const debug = process.env.NODE_ENV !== 'production'
// env里去獲取當前的環境是否需要開啟嚴格模式
// 在發布環境開啟嚴格模式會造成性能上不必要的損失
export default new Vuex.Store({
// 默認導出vuex模塊
modules: {
// 導入模塊
status,
demo
},
strict: debug
// 是否開啟嚴格模式
})
** 構建state模塊 **
這里以demo.js
為例
import * as types from '../types'
// 導入mutations的命名空間
const state = {
// 定義state
demoFollow: false,
// 這里模擬的是關注的狀態,布爾值表示是否關注
demoFollowPending: false
// 是否在請求中(actions是否在執行異步操作)
}
const getters = {
// 定義getters, getters是對state的擴展,可以以state衍生出其他狀態
demoFollowStatus: state => state.demoFollow ? '已關注' : '未關注'
// demoFollowStatus是demoFollow的衍生量,將原來的布爾值映射為'已關注' : '未關注'
}
const mutations = {
// 只有mutations才能操作改變state,mutations是同步執行的
// 所以有關異步的操作請放在actions里執行
[types.DEMO__VUEX_FOLLOW] (state, status = NaN) {
// 使用預定義好的名字來寫mutations方法
state.demoFollow = isNaN(status) ? !state.demoFollow : status
},
[types.DEMO__VUEX_FOLLOW_PENDING] (state, status = NaN) {
// 這里對status傳值做了審查,如沒有傳,則對要改變的布爾值進行取反操作
state.demoFollowPending = isNaN(status) ? !state.demoFollowPending : status
}
}
const actions = {
// actions是可以執行異步操作的,操作完畢后觸發mutations里的方法去改變state的狀態
demoFollowAjax ({commit}, status) {
commit(types.DEMO__VUEX_FOLLOW_PENDING)
// 在異步操作前通過mutations告訴應用,現在正在進行異步操作
setTimeout(() => {
// 利用延時函數模擬異步的ajax操作
commit(types.DEMO__VUEX_FOLLOW_PENDING)
// commit 是在actions里用來觸發mutations的方法
// 告訴應用,異步操作結束
commit(types.DEMO__VUEX_FOLLOW, status)
// 為關注按鈕賦予新的狀態
}, 2000)
}
}
export default {
// 導出整個demo模塊
state,
getters,
actions,
mutations
}
** 這里解釋下mutations里的方法的奇怪寫法,我知道如果對es6于法了解不多這里是會懵逼的 **
const mutations = {
[types.DEMO__VUEX_FOLLOW] (state, status = NaN) {
state.demoFollow = isNaN(status) ? !state.demoFollow : status
}
}
這是對象內方法的簡化寫法,其中types.DEMO__VUEX_FOLLOW
是在types.js
里預定義的,內容如下
export const DEMO__VUEX_FOLLOW = 'DEMO__VUEX_FOLLOW'
export const DEMO__VUEX_FOLLOW_PENDING = 'DEMO__VUEX_FOLLOW_PENDING'
// 其實就是字符串集合,最后用 import * as types from '../types' 方法導入vuex模塊里
// 就變成了一個types對象
上例中全部展開是這樣的
const mutations = {
[types.DEMO__VUEX_FOLLOW]: (state, status = NaN) => {
// [types.DEMO__VUEX_FOLLOW]是提取types.DEMO__VUEX_FOLLOW的值的一種方式
// 在這里[types.DEMO__VUEX_FOLLOW]提取出來就是types.js里預定義的'DEMO__VUEX_FOLLOW'
if (isNaN(status){
state.demoFollow = !state.demoFollow
} else {
state.demoFollow = status
}
}
}
好,到此為止,vuex就已經建立好了,下面就說如何使用了
應用狀態的使用與改變
vuex提供了4個輔助函數
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
是分別用來獲取State, Getters, Actions, Mutations
的map方法
在vue Components里面你可以以這樣的方式來導入需要使用的方法
這4個方法擁有統一的參數格式以及一個統一的返回格式
可以傳入一個數組
mapGetters(['demoFollowStatus'])
// 此方法導出的是一個Getters對象
mapGetters({
demoFollow: 'demoFollowStatus'
})
// 可以通過傳入對象的形式來改變得到的getters方法名
同理,不同的map方法會導出各自的方法
其中mapState, mapGetters
將會導出適用于computed
的方法
而mapMutations, mapActions
將會導出適用于methods
的方法
這里以一個demo組件為例DemoVuexState.vue
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
data () {
return {
}
},
computed: {
// vue的計算屬性,計算屬性內方法的私有變量變動會觸發這個屬性的重新計算
...mapState({
mapStateFollow: ({demo}) => demo.demoFollow,
mapStateFollowPending: ({demo}) => demo.demoFollowPending
}),
// mapState()直接讀取State里的狀態內容
...mapGetters(['demoFollowStatus'])
// mapGetters()通過getters轉化state從而得到你想要的內容
},
methods: {
// vue的方法,可以是一個事件的方法,也可以是一個vuex的方法,也可以是一個普通函數
...mapMutations(['DEMO__VUEX_FOLLOW']),
// 同步的改變狀態
...mapActions(['demoFollowAjax'])
// 異步的改變狀態
}
}
這段代碼是一個demo里的片段,效果大家可以看這個呆萌,如果開心了可以在github庫里加個星,如果有問題可以一起在下方評論里討論討論??