一砸狞、前言
自從學(xué)習(xí)了VUE框架,其中必不可少的會用到vuex這個核心插件,而且在做項目的時候,基本都會使用,可能你會使用vuex狀態(tài)管理喻频,但是對vuex原理存在著或多或少的的疑惑或不解脓恕,這篇文章就針對vuex原理進(jìn)行研究膜宋,希望能幫助到大家,如果有不準(zhǔn)確的地方炼幔,大家多多指教秋茫。。乃秀。
二肛著、Vuex是什么?
Vuex是專門為Vue服務(wù)跺讯,用于管理頁面的數(shù)據(jù)狀態(tài)枢贿、提供統(tǒng)一數(shù)據(jù)操作的生態(tài)系統(tǒng),相當(dāng)于數(shù)據(jù)庫mongoDB刀脏,MySQL等局荚,任何組件都可以存取倉庫中的數(shù)據(jù)。其中vuex類似的 還是有Redux,Redux大多用于React,針對Redux后續(xù)在做補(bǔ)充愈污,現(xiàn)在就讓我們好好了解下Vuex到底是個啥東西耀态?
概念理解性(必讀
Vuex采用MVC模式中的Model層,規(guī)定所有的數(shù)據(jù)必須通過action—>mutaion—>state這個流程進(jìn)行來改變狀態(tài)的暂雹。再結(jié)合Vue的數(shù)據(jù)視圖雙向綁定實現(xiàn)頁面的更新首装。統(tǒng)一頁面狀態(tài)管理,可以讓復(fù)雜的組件交互變的簡單清晰杭跪,同時在調(diào)試時也可以通過DEVtools去查看狀態(tài)仙逻。
在當(dāng)前前端的spa模塊化項目中不可避免的是某些變量需要在全局范圍內(nèi)引用,此時父子組件的傳值涧尿,子父組件間的傳值系奉,兄弟組件間的傳值成了我們需要解決的問題。雖然vue中提供了props(父傳子)commit(子傳父)兄弟間也可以用localstorage和sessionstorage姑廉。但是這種方式在項目開發(fā)中帶來的問題比他解決的問題(難管理缺亮,難維護(hù),代碼復(fù)雜庄蹋,安全性低)更多。vuex的誕生也是為了解決這些問題迷雪,從而大大提高我們vue項目的開發(fā)效率限书。
拋出問題
使用Vuex只需執(zhí)行 Vue.use(Vuex),并在Vue的配置中傳入一個store對象的示例章咧,store是如何實現(xiàn)注入的倦西?
state內(nèi)部是如何實現(xiàn)支持模塊配置和模塊嵌套的?
在執(zhí)行dispatch觸發(fā)action(commit同理)的時候赁严,只需傳入(type, payload)扰柠,action執(zhí)行函數(shù)中第一個參數(shù)store從哪里獲取的粉铐?
如何區(qū)分state是外部直接修改,還是通過mutation方法修改的卤档?
三蝙泼、vue和vuex關(guān)系
看一下這個vue響應(yīng)式的例子,vue中的data 劝枣、methods汤踏、computed,可以實現(xiàn)響應(yīng)式舔腾。
視圖通過點(diǎn)擊事件溪胶,觸發(fā)methods中的increment方法,可以更改state中count的值稳诚,一旦count值發(fā)生變化哗脖,computed中的函數(shù)能夠把getCount更新到視圖。
<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這個響應(yīng)式的例子有什么關(guān)系呢扳还?
我們可以用vuex實現(xiàn)和vue同樣的響應(yīng)式功能才避。
1
其實他們原理時一樣的,vuex中也有四個屬性值:state普办、getters工扎、mutations、actions衔蹲。肢娘。
在沒有actions的情況下:
數(shù)據(jù):state --> data
獲取數(shù)據(jù):getters --> computed
更改數(shù)據(jù):mutations --> methods
視圖通過點(diǎn)擊事件,觸發(fā)mutations中方法舆驶,可以更改state中的數(shù)據(jù)橱健,一旦state數(shù)據(jù)發(fā)生更改,getters把數(shù)據(jù)反映到視圖沙廉。
那么actions,可以理解處理異步拘荡,而單純多加的一層。
既然提到了mutions actions這時候 就不得不提commit撬陵,dispatch這兩個有什么作用呢珊皿?
在vue例子中,通過click事件巨税,觸發(fā)methods中的方法蟋定。當(dāng)存在異步時,而在vuex中需要dispatch來觸發(fā)actions中的方法草添,actions中的commit可以觸發(fā)mutations中的方法驶兜。同步,則直接在組件中commit觸發(fā)vuex中mutations中的方法。
四抄淑、vuex實現(xiàn)
下面我們看下vuex中能像vue中實現(xiàn)改變狀態(tài)屠凶,更新視圖的功能:
Vuex.js
const store = new Vuex.Store({
state: {
count: 0
},
//state的值只能通過mutations來修改
mutations: {
increment(state) {
state.count++
}
},
//this.$store.commit("increment")觸發(fā)mutations中函數(shù)"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>
<!-- 有時候不能直接 強(qiáng)制使用store里面的狀態(tài) this.$store.state.count -->
{{this.$store.getters.getCount}}
</div>
</template>
<script>
export default {
methods: {
increment(){
//this.$store.dispatch("increment")觸發(fā)actions函數(shù)"increment"
this.$store.dispatch("increment")
}
}
}
</script>
五、源碼分析:
現(xiàn)在我們已經(jīng)了解vuex能實現(xiàn)和像vue雙向數(shù)據(jù)綁定–更新試圖的功能肆资,下面我們重點(diǎn)說說vuex源碼的實現(xiàn):
5.1矗愧、store注入組件install方法
解答問題:vuex的store是如何注入到組件中的?
首先使用vuex,需要安裝插件:
Vue.use(Vuex); // vue的插件機(jī)制,安裝vuex插件
當(dāng)ues(Vuex)時候迅耘,會調(diào)用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機(jī)制纽哥,借助vue組件的生命周期 鉤子 beforeCreate 完成的。即 每個vue組件實例化過程中栖秕,會在 beforeCreate 鉤子前調(diào)用 vuexInit 方法春塌。
解答問題:vuex的state和getters是如何映射到各個組件實例中響應(yīng)式更新狀態(tài)呢?
5.2簇捍、new vue實現(xiàn)雙向數(shù)據(jù)綁定:
this._s = new Vue({
data: {
// 只有data中的數(shù)據(jù)才是響應(yīng)式
state: options.state
}
})
5.3只壳、getters實現(xiàn)
//實現(xiàn)getters原理
let getters = options.getters || {}
// console.log(getters);
// this.getters = getters; //不是直接掛載到 getters上 這樣只會拿到整個 函數(shù)體
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, {
// 當(dāng)你要獲取getterName(myAge)會自動調(diào)用get方法
// 箭頭函數(shù)中沒有this
get: () => {
return getters[getterName](this.state)
}
})
})
從上面源碼,我們可以看出Vuex的state狀態(tài)是響應(yīng)式暑塑,是借助vue的data是響應(yīng)式吼句,將state存入vue實例組件的data中;Vuex的getters則是借助vue的計算屬性computed實現(xiàn)數(shù)據(jù)實時監(jiān)聽事格。
5.4惕艳、mutations實現(xiàn)
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)
}
})
實現(xiàn)同步加:
動態(tài)效果圖:
5.5、actions實現(xiàn)
// actions的原理
let actions = options.actions || {}
this.actions = {};
forEach(actions,(actionName,value)=>{
this.actions[actionName] = (payload)=>{
value(this,payload)
}
})
5.6驹愚、commit dispatch的實現(xiàn)
commit(type,payload){
this.mutations[type](payload)
}
// type是actions的類型
dispatch=(type,payload)=>{
this.actions[type](payload)
}
六远搪、原理總結(jié):
Vuex是通過全局注入store對象,來實現(xiàn)組件間的狀態(tài)共享逢捺。在大型復(fù)雜的項目中(多級組件嵌套)谁鳍,需要實現(xiàn)一個組件更改某個數(shù)據(jù),多個組件自動獲取更改后的數(shù)據(jù)進(jìn)行業(yè)務(wù)邏輯處理劫瞳,這時候使用vuex比較合適倘潜。假如只是多個組件間傳遞數(shù)據(jù),使用vuex未免有點(diǎn)大材小用志于,其實只用使用組件間常用的通信方法即可涮因。
附加參考vuex源碼,可以調(diào)試一下的
參考鏈接:https://www.cnblogs.com/hjson/p/10500770.html
面試常見:https://blog.csdn.net/xu838209490/article/details/80334283
————————————————
版權(quán)聲明:本文為CSDN博主「凌晨四點(diǎn)半er」的原創(chuàng)文章恨憎,遵循CC 4.0 BY-SA版權(quán)協(xié)議蕊退,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_44667072/article/details/101164766