自從學習了VUE框架,其中必不可少的會用到vuex這個核心插件,並且在作項目的時候,基本都會使用,可能你會使用vuex狀態管理,可是對vuex原理存在着或多或少的的疑惑或不解,這篇文章就針對vuex原理進行研究,但願能幫助到你們,若是有不許確的地方,你們多多指教。。。html
Vuex是專門爲Vue服務,用於管理頁面的數據狀態、提供統一數據操做的生態系統,至關於數據庫mongoDB,MySQL等,任何組件均可以存取倉庫中的數據。其中vuex相似的 仍是有Redux,Redux大多用於React,針對Redux後續在作補充,如今就讓咱們好好了解下Vuex究竟是個啥東西?前端
Vuex採用MVC模式中的Model層,規定全部的數據必須經過action--->mutaion--->state這個流程進行來改變狀態的。再結合Vue的數據視圖雙向綁定實現頁面的更新。統一頁面狀態管理,可讓複雜的組件交互變的簡單清晰,同時在調試時也能夠經過DEVtools去查看狀態。vue
在當前前端的spa模塊化項目中不可避免的是某些變量須要在全局範圍內引用,此時父子組件的傳值,子父組件間的傳值,兄弟組件間的傳值成了咱們須要解決的問題。雖然vue中提供了props(父傳子)commit(子傳父)兄弟間也能夠用localstorage和sessionstorage。可是這種方式在項目開發中帶來的問題比他解決的問題(難管理,難維護,代碼複雜,安全性低)更多。vuex的誕生也是爲了解決這些問題,從而大大提升咱們vue項目的開發效率。git
使用Vuex只需執行 Vue.use(Vuex),並在Vue的配置中傳入一個store對象的示例,store是如何實現注入的?
state內部是如何實現支持模塊配置和模塊嵌套的?
在執行dispatch觸發action(commit同理)的時候,只需傳入(type, payload),action執行函數中第一個參數store從哪裏獲取的?
如何區分state是外部直接修改,仍是經過mutation方法修改的?
複製代碼
看一下這個vue響應式的例子,vue中的data 、methods、computed,能夠實現響應式。github
視圖經過點擊事件,觸發methods中的increment方法,能夠更改state中count的值,一旦count值發生變化,computed中的函數可以把getCount更新到視圖。web
<div id="app">
<button @click="increment"></button>
{{getcount}}
</app>
new Vue({
el: "#app",
// state
data () {
return {
count: 0
}
},
// view
computed: {
getCount(){
return this.count
}
},
// actions
methods: {
increment () {
this.count++
}
},
})
複製代碼
那麼vuex又和vue這個響應式的例子有什麼關係呢?面試
咱們能夠用vuex實現和vue一樣的響應式功能。
複製代碼
其實他們原理時同樣的,vuex中也有四個屬性值:state、getters、mutations、actions。。vuex
在沒有actions的狀況下:數據庫
視圖經過點擊事件,觸發mutations中方法,能夠更改state中的數據,一旦state數據發生更改,getters把數據反映到視圖。json
那麼actions,能夠理解處理異步,而單純多加的一層。
既然提到了mutions actions這時候 就不得不提commit,dispatch這兩個有什麼做用呢?
在vue例子中,經過click事件,觸發methods中的方法。當存在異步時,而在vuex中須要dispatch來觸發actions中的方法,actions中的commit能夠觸發mutations中的方法。同步,則直接在組件中commit觸發vuex中mutations中的方法。
下面咱們看下vuex中能像vue中實現改變狀態,更新視圖的功能:
Vuex.js
const store = new Vuex.Store({
state: {
count: 0
},
//state的值只能經過mutations來修改
mutations: {
increment(state) {
state.count++
}
},
//this.$store.commit("increment")觸發mutations中函數"increment"
actions: {
increment({commit}) {
commit("increment"); //this.$store.commit("increment")
}
},
//經過getter中的方法來獲取state值
getters: {
getCount(state) {
return state.count
}
}
})
export default store
複製代碼
App.vue
<template>
<div id="app">
<button @click="increment">增長</button>
<!-- 有時候不能直接 強制使用store裏面的狀態 this.$store.state.count -->
{{this.$store.getters.getCount}}
</div>
</template>
<script>
export default {
methods: {
increment(){
//this.$store.dispatch("increment")觸發actions函數"increment"
this.$store.dispatch("increment")
}
}
}
</script>
複製代碼
如今咱們已經瞭解vuex能實現和像vue雙向數據綁定--更新試圖的功能,下面咱們重點說說vuex源碼的實現:
解答問題:vuex的store是如何注入到組件中的?
首先使用vuex,須要安裝插件:
Vue.use(Vuex); // vue的插件機制,安裝vuex插件
複製代碼
當ues(Vuex)時候,會調用vuex中的install方法,裝在vuex! 下面時install的核心源碼:
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.store) {
//找到根組件 main 上面掛一個$store
this.$store = this.$options.store
// console.log(this.$store);
} else {
//非根組件指向其父組件的$store
this.$store = this.$parent && this.$parent.$store
}
}
})
複製代碼
可見,store注入 vue的實例組件的方式,是經過vue的 mixin機制,藉助vue組件的生命週期 鉤子 beforeCreate 完成的。即 每一個vue組件實例化過程當中,會在 beforeCreate 鉤子前調用 vuexInit 方法。
解答問題:vuex的state和getters是如何映射到各個組件實例中響應式更新狀態呢?
this._s = new Vue({
data: {
// 只有data中的數據纔是響應式
state: options.state
}
})
複製代碼
//實現getters原理
let getters = options.getters || {}
// console.log(getters);
// this.getters = getters; //不是直接掛載到 getters上 這樣只會拿到整個 函數體
this.getters = {};
// console.log(Object.keys(getters)) // ["myAge","myName"]
Object.keys(getters).forEach((getterName) => {
// console.log(getterName) // myAge
// 將getterName 放到this.getters = {}中
// console.log(this.state);
Object.defineProperty(this.getters, getterName, {
// 當你要獲取getterName(myAge)會自動調用get方法
// 箭頭函數中沒有this
get: () => {
return getters[getterName](this.state)
}
})
})
複製代碼
從上面源碼,咱們能夠看出Vuex的state狀態是響應式,是藉助vue的data是響應式,將state存入vue實例組件的data中;Vuex的getters則是藉助vue的計算屬性computed實現數據實時監聽。
let mutations = options.mutations || {}
// console.log(mutations);
this.mutations = {};
Object.keys(mutations).forEach(mutationName=>{
// console.log(mutationName);
this.mutations[mutationName] = (payload) =>{
this.mutations[mutationName](this.state,payload)
}
})
複製代碼
實現同步加: 動態效果圖:
// actions的原理
let actions = options.actions || {}
this.actions = {};
forEach(actions,(actionName,value)=>{
this.actions[actionName] = (payload)=>{
value(this,payload)
}
})
複製代碼
commit(type,payload){
this.mutations[type](payload)
}
複製代碼
// type是actions的類型
dispatch=(type,payload)=>{
this.actions[type](payload)
}
複製代碼
Vuex是經過全局注入store對象,來實現組件間的狀態共享。在大型複雜的項目中(多級組件嵌套),須要實現一個組件更改某個數據,多個組件自動獲取更改後的數據進行業務邏輯處理,這時候使用vuex比較合適。假如只是多個組件間傳遞數據,使用vuex未免有點大材小用,其實只用使用組件間經常使用的通訊方法便可。
附加參考vuex源碼,能夠調試一下的