組件是Vue最強大的功能之一,而組件實例的做用域是相互獨立的,意味着不一樣組件之間的數據是沒法相互使用。組件間如何傳遞數據就顯得相當重要,這篇文章主要是介紹Vuex。儘可能以通俗易懂的實例講述這其中的差異,但願對小夥伴有些許幫助。html
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。vue
一個簡單的 Vue 計數應用開始:面試
new Vue({ // state data () { return { count: 0 } }, // view template: ` <div>{{ count }}</div> `, // actions methods: { increment () { this.count++ } } })
這個狀態自管理應用包含如下幾個部分:vuex
state,驅動應用的數據源;
view,以聲明方式將 state 映射到視圖;
actions,響應在 view 上的用戶輸入致使的狀態變化。
segmentfault
state的數據會在 view上顯示出來,用戶會根據 view 上的內容進行操做,從而觸發 actions,接着再去影響 state(vue 是單向數據流的方式驅動的)。緩存
當咱們的應用遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞。下面的圖,是把組件的共享狀態抽取出來,以一個全局單例模式管理。
app
1. state
state:頁面狀態管理容器對象。集中存儲Vue components中data對象的零散數據,以進行統一的狀態管理。頁面顯示所需的數據從該對象中進行讀取。異步
<div> {{ $store.state.count }} </div> console.log(this.$store.state.count)
2. getters
getters:Vuex 容許咱們在 store 中定義「getter」(能夠認爲是 store 的計算屬性)。就像計算屬性同樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算。(getters從表面是得到的意思,能夠把他看做在獲取數據以前進行的一種再編輯,至關於對數據的一個過濾和加工。getters就像計算屬性同樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算。)函數
定義getter:this
getters: { done(state) { return state.count + 1; }, }
3. mutations
mutations:更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutation 很是相似於事件:每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 變動狀態 state.count++ } } })
組件經過commit提交mutations的方式來請求改變state
this.$store.commit('increment')
提交載荷(Payload)
mutations方法中是能夠傳參的,具體用法以下:
mutations: { // 提交載荷 Payload add(state, n) { state.count += n } }, this.$store.commit('add', 10)
4.Action
Action:相似於 mutation,不一樣在於Action 提交的是 mutation,而不是直接變動狀態;Action 能夠包含任意異步操做。
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
不一樣於mutations使用commit方法,actions使用dispatch方法。
this.$store.dispatch('incrementAsync')
context
context是與 store 實例具備相同方法和屬性的對象。能夠經過context.state和context.getters來獲取 state 和 getters。
以載荷形式分發
incrementAsyncWithValue (context, value) { setTimeout(() => { context.commit('add', value) }, 1000) } this.$store.dispatch('incrementAsyncWithValue', 5)
5.Module
因爲使用單一狀態樹,應用的全部狀態會集中到一個比較大的對象。當應用變得很是複雜時,store 對象就有可能變得至關臃腫。
爲了解決以上問題,Vuex 容許咱們將 store 分割成模塊(module)。每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行一樣方式的分割:
const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的狀態 store.state.b // -> moduleB 的狀態
模塊的局部狀態
對於模塊內部的 mutation 和 getter,接收的第一個參數是模塊的局部狀態對象。
const moduleA = { state: { count: 0 }, mutations: { increment (state) { // 這裏的 `state` 對象是模塊的局部狀態 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } }
在src目錄下建立一個store文件夾。
store/store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0, show: '' }, getters: { counts: (state) => { return state.count } }, mutations: { increment: (state) => { state.count++ }, decrement: (state) => { state.count-- }, changVal: (state, v) => { state.show = v } } }) export default store
state就是咱們的須要的狀態,狀態的改變只能經過提交mutations,例如:
increase() { this.$store.commit('increment') }
帶有載荷的提交方式:
changObj () { this.$store.commit('changVal', this.obj) }
載荷也能夠是一個對象,這樣能夠提交多個參數。
changObj () { this.$store.commit('changVal', { key:'' }) }
在main.js中引入store.js
import store from './store/store' export default new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
在組件中使用
在組建能夠經過$store.state.count得到狀態
更改狀態只能以提交mutation的方式。
<div class="store"> <p> {{$store.state.count}} </p> <button @click="increase"><strong>+</strong></button> <button @click="decrease"><strong>-</strong></button> <hr> <h3>{{$store.state.show}}</h3> <input placeholder="請輸入內容" v-model="obj" @change="changObj" clearable> </input> </div> </template> <script> export default { data () { return { obj: '' } }, methods: { increase() { this.$store.commit('increment') }, decrease() { this.$store.commit('decrement') }, changObj () { this.$store.commit('changVal', this.obj) } } } </script>
不少時候 , $store.state.dialog.show 、$store.dispatch('switch_dialog') 這種寫法又長又臭 , 很不方便 , 咱們沒使用 vuex 的時候 , 獲取一個狀態只須要 this.show , 執行一個方法只須要 this.switch_dialog 就好了 , 使用 vuex 使寫法變複雜了 ?使用 mapState、mapGetters、mapActions 就不會這麼複雜了。
以 mapState 爲例 :
<template> <el-dialog :visible.sync="show"></el-dialog> </template> <script> import {mapState} from 'vuex'; export default { computed:{ //這裏的三點叫作 : 擴展運算符 ...mapState({ show:state=>state.dialog.show }), } } </script>
至關於 :
<template> <el-dialog :visible.sync="show"></el-dialog> </template> <script> import {mapState} from 'vuex'; export default { computed:{ show(){ return this.$store.state.dialog.show; } } } </script>
mapGetters、mapActions 和 mapState 相似 , mapGetters 通常也寫在 computed 中 , mapActions 通常寫在 methods 中。
Vuex官方文檔