vuex的應用場景,你們可能或多或少知道,用來管理一些全局數據,或者多個頁面都會使用到的數據,好比,咱們項目中常見的用戶信息,一般使用vuex來管理。html
這裏,咱們思考一個問題,如何沒有vuex,還有哪些方式能夠實現一些公共數據的管理?vue
以上兩種方式,雖然能夠用來管理咱們的全局數據,可是隨着項目愈來愈複雜,全局數據愈來愈多,目前這樣的管理方式成本仍是有些高,因此,咱們須要一套系統化的,流程化的機制來管理全局數據,而vuex就是爲此而誕生的。vuex
vuex的優勢:它不只僅是一個全局數據的管理器,同時它最大的特性是支持響應式的,也就是說使用vuex管理的數據若是發生改變,那麼引入這些數據的組件都會自動刷新,vue-cli
首先,咱們經過上圖要明白如下幾點:npm
以上基本覆蓋了vuex的經常使用知識點,接下來,咱們來經過一個具體的代碼案例來深刻理解一下。後端
咱們來實現一個簡單的計數器,點擊能夠增長數字, 首先,本次代碼都在基於vue-cli3生成的項目模版去實現的。api
第一步:安裝vuex緩存
npm i vuex --save
複製代碼
第二步:引入vuexbash
//main.js
import App from './App.vue'
Vue.config.productionTip = false
//vuex的使用
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
//全部的數據都存放在state中
state: {
count: 0
},
//mutations實現同步操做
mutations: {
increment (state, params) {
state.count += params;
}
},
//actions中實現一些異步操做
actions: {
increment ({state}, params) {
setTimeout(() => {
state.count += params;
}, 3000)
}
},
getters: {
doubleCount (state) {
return state.count * 2;
}
}
});
new Vue({
store,
render: h => h(App),
}).$mount('#app')
複製代碼
//app.vue
<template>
<div id="app">
<span>count: {{count}}</span>
<button @click="addCount1">count++</button>
<br>
<span>doubleCount: {{doubleCount}}</span>
<button @click="addCount2">count++</button>
</div>
</template>
<script>
export default {
name: 'app',
computed: {
count () {
return this.$store.state.count;
},
doubleCount () {
return this.$store.getters.doubleCount;
}
},
methods: {
addCount1 () {
this.$store.commit('increment', 2); //mutations經過commit觸發
},
addCount2 () {
this.$store.dispatch('increment', 2); //actions經過dispatchc觸發
}
}
}
</script>
複製代碼
經過上面的代碼,咱們要清楚如下幾點:app
也就是說:咱們一般能夠經過state和getters來獲取全局數據,也能夠經過mutations和actions修改全局數據,mutations是同步操做,actions是異步操做。
import Vuex from 'vuex';
const store = new Vuex.Store({
state: {},
mutations: {}
...
});
複製代碼
new Vue({
store,
render: h => h(App),
}).$mount('#app')
複製代碼
問題:
經過上面的學習,咱們知道了,全部狀態變量都是定義在store中的state屬性中,那麼,如何獲取state中的數據呢? //第一種方式:
export default {
computed: {
count () {
return this.$store.state.count;
},
doubleCount () {
return this.$store.getters.doubleCount;
},
number () {
return this.$store.state.number;
}
},
}
即直接在computed計算屬性中返回所需數據,缺點就是:若是狀態樹愈來愈多,每一個屬性都須要咱們在computed中聲明而且返回一次,不太友好,解決方案就是mapState
複製代碼
//第二種方式:
import {mapState} from 'vuex';
export default {
computed: mapState([
'count',
'doubleCount',
'number'
]),
}
同時,若是想自定義別名,也能夠給mapState傳入一個對象,自定義處理,可是上面的寫法,咱們就沒法在computed聲明當前vue實例下本身的計算屬性了,解決方案就是rest運算符...
複製代碼
//第三種方式:
import {mapState} from 'vuex';
export default {
computed: {
...mapState([
'count',
'number'
]),
...mapGetters([
'doubleCount'
]),
//也能夠自定義其餘計算屬性
},
}
複製代碼
經過上面,咱們知道了能夠有不少種不一樣的寫法去讀取state裏面的數據,getters也相似,上面第三種方式也有體現,咱們須要知道各類寫法的優缺點,同時,在實際項目中,咱們只須要採用最優寫法便可,即第三種方式。
Getter與State的做用都是定義一些全局使用的數據,Getter和State的關係就相似於computed和data的關係,Getter的返回值會被緩存起來,只有它所依賴的state中的數據發生變化纔會跟着從新計算。
咱們只須要明白Getter的做用以及與State的區別便可,寫法和State相似,參考上面便可。
上面咱們知道了,能夠經過state和getter來定義和讀取狀態,那麼接下來,如何修改狀態呢?記住一句話:更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation.
首先,要說明一下mutation中的幾個概念:
咱們在具體的代碼中說明:
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
//increment就是在mutation中定義的事件類型
increment (state, payload) {
state.count += payload.amount
}
}
})
store.commit('increment', {
amount: 10 // commit中傳的參數就是載荷
})
複製代碼
接下來,咱們要說一下在組件中mutation的幾種寫法: //第一種
export default {
methods: {
addCount () {
this.$store.commit('increment', 2);
}
}
}
複製代碼
//第二種方式:
import {mapMutations} from 'vuex';
export default {
methods: {
...mapMutations([
'increment'
]),
addCount () {
this.increment(2);
}
}
}
複製代碼
注意點:在mutation中都是同步事件,由於mutation的做用就是能夠捕捉到每一次的提交或者修改記錄,若是是異步事件,devtool很難捕捉到,這時就要用到Action了
Action和Mutation都是用來修改狀態的,區別就是action中一般是一些異步事件,而且經過dispatch去分發事件,固然,有一點,咱們要知道actions內部也是經過提交mutation去修改數據的。
這裏,具體寫法就不說了,和mutation相似。
經過上面的講解,咱們都知道了,修改state的惟一路徑就是 提交mutation,固然,若是咱們直接修改了state裏面的值,在非嚴格模式下,也是能夠生效的,可是不建議這麼作,在嚴格模式下,vue會直接報錯
還有一點:表單裏使用v-model雙向綁定的若是是state裏面的數據,這時,若是在嚴格模式下,會直接報錯的,由於數據修改完,v-model內部就默認直接修改了state裏面的數據,具體解決方案,能夠直接參考官網:vuex.vuejs.org/zh/guide/fo…
vuex其實自己內容是比較簡單的,可是因爲咱們引入mapState,mapGetter等map寫法以後,可能會容易產生混淆,致使感受vuex相關概念較多,沒法真正理清,這裏咱們在總結一下:
首先vuex的核心就是store,也叫倉庫,他就是一個容器,裏面包含着state,getter,mutation,action等屬性,
- 首先這些狀態都定義在哪裏呢?
即直接定義在state中就能夠啦
- 定義完之後,怎麼在組件中讀取狀態呢?
經過this.store.getter的方式去讀取,固然爲了寫法更加間接,咱們引入了mapState和mapGetter。
- 定義完之後,怎麼在組件中修改狀態呢?
vuex只支持一種方式:那就是commit mutation,action內部自己也是commit mutaition, 固然,依然是爲了寫法間接,咱們又引入了mapMutations和mapActions。
經過上面的總結,咱們知道了map系列api,都只是爲了如何更簡潔的讀取和修改狀態,暫時拋開這一部分,咱們發現,其實vuex的內容其實很簡單。
這一節,咱們主要看一下vuex的實現原理,同時,實現也能夠簡易版的vuex。
經過上面的介紹,咱們知道了vuex中的狀態state和單純的全局對象仍是不一樣的,主要體如今:
那,咱們接下來看看vuex具體是如何實現響應式的?其實內部就是經過vue的響應式機制去實現的。
下面,咱們能夠手動實現一個簡易版的vuex
import Vue from 'vue'
const Store = function Store (options = {}) {
const {state = {}, mutations={}} = options
this._vm = new Vue({
data: {
$$state: state
},
})
this._mutations = mutations
}
Store.prototype.commit = function(type, payload){
if(this._mutations[type]) {
this._mutations[type](this.state, payload)
}
}
Object.defineProperties(Store.prototype, {
state: {
get: function(){
return this._vm._data.$$state
}
}
});
export default {Store}
複製代碼
經過上面的代碼,咱們看到,其實vuex內部也是經過new Vue()的方式,將state存儲在vue實例的data中,從而實現響應式的。