2017年對於Vue註定是不平凡的一年。憑藉着自身簡介、輕量、快速等特色,Vue儼然成爲最火的前端MVVM開發框架。隨着Vue2.0的release,愈來愈多的項目開始採用Vue做爲他們的前端框架。而做爲Vue生態中最重要的一環,Vuex漸漸進入你們的視野。html
數據管理模式前端
在正式開始介紹Vuex以前,有必要介紹一下數據管理模式的前世此生。vue
當你在開發應用程序時,你必定會分解出不少組件進行開發,而各個組件之間想必在邏輯上多少是有關係的。那麼組件之間的「通訊」,就成了待解決問題。之前咱們試圖用事件廣播來作,但隨之而來的問題是,在應用不斷的擴展、變化中,事件變得愈來愈複雜,愈來愈不可預料,以致於愈來愈難調試,愈來愈難追蹤錯誤。這固然不是咱們想要的,咱們但願應用的各個部分都易維護、可擴展、好調試、能預測。因而數據管理模式應運而生。git
圖1是最簡單的組件關係,b是a的子組件,而c是b的子組件。在咱們不引入任何數據管理模式以前,c組件要拿到a組件的數據只能由a先傳給b,在由b傳給c。若是組件樹變得複雜,可想而知這將是一場災難。看似嚴謹的父子結構其實嚴格限制了數據的流動方式。github
圖2是最簡單的數據管理模式,全部數據將統一交給全局store來管理。a和c組件如今直接修改store裏的數據,而且經過mapState從store中抓取本身感興趣的數據到本身的組件中。而b組件,若是它對a、c組件的數據毫無興趣,則能夠作到徹底解耦。vuex
隨着數據管理的進一步發展和演變,有一種叫單向數據流的東西冒了出來。圖3就是一個表示「單向數據流」理念的極簡示意。單向數據流要求各組件間的數據走向永遠是單向的,可預期的。你不能直接改變 store 中的狀態。改變 store 中的狀態的惟一途徑就是顯式地提交Actions。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以更好地瞭解咱們的應用。緩存
此次咱們的主人公Vuex能夠說是單向數據流的最佳實踐者。前端框架
Vuex是什麼?框架
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。Vuex背後的基本思想,就是前面所說的單向數據流。圖4就是Vuex實現單向數據流的示意圖。異步
接下來,咱們將會更深刻地探討一些核心概念。讓咱們先從Store概念開始。
Store
每個 Vuex 應用的核心就是 store(倉庫)。「store」基本上就是一個容器,它包含着你的應用中大部分的狀態 (state) 。
安裝 Vuex 以後,讓咱們來建立一個最簡單的 store。建立過程直截了當——僅須要提供一個初始 state 對象和一些 mutation:
如今,你能夠經過 store.state 來獲取狀態對象,以及經過 store.commit 方法觸發狀態變動:
因爲 store 中的狀態是響應式的,在組件中調用 store 中的狀態簡單到僅須要在計算屬性中返回便可。觸發變化也僅僅是在組件的 methods 中提交 mutation。
State
Vuex 使用單一狀態樹——是的,用一個對象就包含了所有的應用層級狀態。至此它便做爲一個「惟一數據源 (SSOT)」而存在。單一狀態樹讓咱們可以直接地定位任一特定的狀態片斷,在調試的過程當中也能輕易地取得整個當前應用狀態的快照。
那麼咱們如何在 Vue 組件中展現狀態呢?因爲 Vuex 的狀態存儲是響應式的,從 store 實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態:
Getter
有時候咱們須要從 store 中的 state 中派生出一些狀態,例如對列表進行過濾並計數:
若是有多個組件須要用到此屬性,咱們要麼複製這個函數,或者抽取到一個共享函數而後在多處導入它——不管哪一種方式都不是很理想。
Vuex 容許咱們在 store 中定義「getter」(能夠認爲是 store 的計算屬性)。就像計算屬性同樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算。
Getter 會暴露爲 store.getters 對象:
Mutation
Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutation 很是相似於事件:每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數(handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數,payload做爲第二個參數(額外的參數):
一條重要的原則就是要記住 mutation 必須是同步函數。
Action
Action 相似於 mutation,不一樣在於:
1.Action 提交的是 mutation,而不是直接變動狀態。
2.Action 能夠包含任意異步操做。
讓咱們來註冊一個簡單的 action:
Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit 提交一個 mutation,或者經過 context.state 和 context.getters 來獲取 state 和 getters。
咱們能夠在 action 內部執行異步操做:
今天的目標
這是一個記憶小遊戲,來自leftstick的vue-memory-game,github地址:https://github.com/leftstick/vue-memory-game。今天咱們就這個小遊戲來詳細講解下vuex的實現。
組件分解
咱們根據分解圖,先把要實現的組件挨個兒列出來:
Game, 最外層的遊戲面板
Dashboard, 上面的logo,遊戲進度,最佳戰績的容器
Logo,左上角的logo
MatchInfo, 正中上方的遊戲進度組件
Score, 右上角的最佳戰績組件
Chessboard, 正中大棋盤
Card, 中間那十六個棋牌
PlayStatus, 最下方的遊戲狀態信息欄
目錄結構
讓咱們聚焦紅框中關於Vuex的這一部分。接下來咱們將結合Card.vue和Chessboard.vue這兩個核心組件進行。
store/index.js
store的建立並無什麼複雜的邏輯,而state就是這個項目須要維護的整個數據。初始化cards的結構我簡要的整合了一下:
你能夠選擇初始化store的時候直接帶進去,也能夠像做者同樣從入口處reset一遍數據,這裏就不詳細展開了。
Chessboard.vue
Card.vue
我在源碼上增長了一些註釋,方便你們理解。
mapGetter和mapActions只是一些輔助函數,能夠減小一些this.$store和dispatch action之類比較重複的代碼,這些輔助函數能夠幫助vuex應用的更加簡便。
相比與這些無關緊要的噱頭,咱們更關心卡片被點擊的時候發生了什麼?this.flipCard()後數據流向了哪裏?
數據流動
當卡片被點擊時,vue component 實則 dispatch出了一個action,而咱們的數據,做爲載荷(參數),也只能隨波逐流了。
他首先來到了第一站:actions,然而actions卻說你不須要什麼異步處理,能夠去下一站了。(若是沒有異步操做,其實能夠少走一站)
actions處理函數
數據沒有灰心,很快他就來到了mutaions。
mutaions欣喜若狂:你在這等着,待我處理好了你再上路。
mutations處理函數
不一會,數據就改頭換面了,但如何告訴vue components我發生變化了呢?迷茫的數據找到了getter。getter哈哈大笑:你在我這的狀態存儲是響應式的,只要vue components在計算屬性中應用了你,他們就能第一時間知道你的狀態變動哦。
getter生成計算屬性(若是沒有派生出其餘狀態,能夠不用getter)
components狀態更新
結尾
經過這個記憶小遊戲,但願你們對Vuex有一個基本的理解。若是你熟悉Redux的話,掌握Vuex應該不難,由於Vuex和Redux基本思想是一致的,實現方式也是大同小異。但Vuex只適用於Vue,沒有Redux那麼泛用罷了。
網易雲大禮包:https://www.163yun.com/gift
本文來自網易雲社區,經做者劉凌陽受權發佈
相關文章:
【推薦】 如何從「點子」落地到「執行」?—完整解析1個手遊傳播類mini項目的進化
【推薦】 非對稱加密與證書(上篇)
【推薦】 Wireshark對HTTPS數據的解密