1、思想:基于響應式的原理:所有的狀態的變更都是因為數據的變化引起的
。
2、背景:在傳統的vue應用中,我們可能定義許多component
,而每個component可能是這樣的:
var component_library_title = {
props: ['text'],
data:{
a:'',
b:''
},
template: '<div>{{text}}</div>'
};
這樣,在不用的component中,就會出現屬于不用vue的組件管理的data數據,這樣,如果在父子component或者兄弟component中進行數據傳遞的時候,會比較混亂。
3、解決:將所有的data交給vuex管理。
- 如何獲取數據:
因為在vue的computed
鉤子中,其中的方法會在管理的數據源發生變更的時候,主動調用并更新數據,所以這樣正好,我們可以知道vuex管理的store發生變更的時候,數據如何變化。
- 如何更改數據:
通過commit或者dispatch去發送事件更改數據源,而不建議直接調用類似store.data.a
去更改數據。
核心概念
State
單一狀態樹:一個應用只對應一個狀態樹,且這種思想和組件化并不沖突!
1、將State注冊到所有的子組件中
const app = new Vue({
el: '#app',
// 把 store 對象提供給 “store” 選項,這可以把 store 的實例注入所有的子組件
store,
components: { Counter },
template: `
<div class="app">
<counter></counter>
</div>
`
})
如果想直接訪問store實例中的屬性,可以這樣:this.$store.state.屬性
進行訪問。
2、使用mapState
3、在子component中使用store中的state
你需要在子component
中的computed
鉤子中創建方法
computed: {
count () {
return this.$store.state.count
}
}
然后在需要使用的地方,直接{{count}}
就可以了。
Getters
其實是一種規范吧:
本來我們在子component中就能夠通過如上的方法獲取store的state的屬性,但是,假設我們希望對直接定義在store中的屬性進行一些操作(這里官方網站說的是一些filter操作等),我們希望不要再修改
mapState
或者直接通過return this.$store.state.count
來進行數據的獲取或者修改。于是就使用
getter
進行數據的操作并裝換。注意到,我們在修改一個的時候,可能需要同時和其他的store中的state下面的數據進行以前操作,這就意味著,我們需要拿到
state
這個對象。而的確是這樣的,getters中允許我們在定義的方法中帶有
state
參數
1、定義
getters: {
count(state){
return state.count + 1;
},
}
2、使用
computed: {
getMessage(){
return this.$store.state.count;
},
}
你需要在子component中的computed
鉤子中定義方法,這樣就能直接使用了。
Mutations
我們會返現,在Vuex
中,只有Getter
的定義,而沒有類似于Setter
的定義.
其實,這里的Mutations
就是Setter
的實現.
雖然我們能夠通過this.$store.state.屬性
獲取到某個屬性,并進行修改,但是,vuex強烈建議我們不要這樣做。
1、直接修改在$store.state
中的值
我們直接在子component中定義了一個方法,用來直接$store.state
中的值。
- html中
template: '<div>{{getMessage}}并且:{{getMessage1}}' +'<button @click="changeMessage">修改</button>' +'</div>',
- js中
methods: {
changeMessage(){
console.log(this.$store.state.count);
this.$store.state.count = 100;
}
}
我們發現,在調用changeMessage
后,this.$store.state.count
變成了100。
說明我們本身是能夠直接調用this.$store.state.count
進行state中值得修改的。
Note:但是,Vuex建議我們不要這樣做,如果需要修改
this.$store.state
中的值,建議在store中的Mutations
鉤子中進行方法的定義來完成。
2、使用Mutations
mutations: {
increment (state) {
// 變更狀態
state.count++
}
}
注意在定義方法的時候,可以攜帶state
參數。
3、觸發方法
方法一:使用方法名稱
在本component中
store.commit('方法名稱');
在子component中
this.$store.commit('方法名稱');
方法二:使用對象
store.commit({
type:'方法名稱',
...
});
4、使用常量定義mutations中的方法名
mutations: {
[INCREMENT](state){
state.count++;
},
[DECREMENT](state){
state.count--;
},
},
這樣,就會比較方便的進行管理了。
Actions
顧名思義,這也是一個可以改變state中屬性的方法集。但是mutations中不是已經提供了可用的方法集合了嘛?!
但是,如果你在Mutations中寫就的方法集合中某個方法是異步的,那么我們不建議將異步方法寫在Mutations
中(雖然的確是可以的)。
那么,我們需要將這些方法寫在Actions
中。
1、寫法
actions: { asyncIncrement(context){ console.log('asyncIncrement'); context.commit('INCREMENT'); }}
2、調用
這里稱之為“分發”。
asyncIncrement(){
store.dispatch({
type: 'asyncIncrement',
amount: 4,
});
}
3、在模塊中分發消息
changeMessageAsync(){
console.log('異步修改');
this.$store.dispatch('asyncIncrement')
}
這樣,直接使用this.$store.dispatch('asyncIncrement')
進行分發。
表單操作
傳統方法(不按照Vuex的思路去管理數據)
Vuex的思維方式:我們需要將數據統一管理,使用computed
時刻觀察數據的變化,并通過commit
或者dispatch
的方式改變數據。
那么我們只需要使用v-model
就能方便簡單的實現了。
但是一旦我們在某處使用了vuex,并且我們希望在任何地方也使用vuex的思維進行數據的管理。
那么問題就來了。
- 問題來了:
<input type="text" v-model="bookSerialNumber"/>
computed:{ bookSerialNumber(){
return this.$store.state.book.serialNumber;
},
},
我們只能通過計算屬性(computed)計算出當前this.$store.state.book.serialNumber
的值,而無法實現該值的修改。
除非我們在方法
bookSerialNumber
中通過直接改變this.$store.state.book.serialNumber
的值,但是這樣是明顯不符合vuex方法論的。
vuex的解決
<input type="text" @input='bookNameInputChange' :value='bookName'/>
為你的表單中的某一項:
- 使用
:value
單向綁定某個在computed
中實現的計算屬性; - 使用
@input
監聽控件的輸入的變化,這樣就實現了setter的方法,我們通過在mutations
中定義的屬性對屬性進行控制,假設這個改變的過程是異步的,你需要在actions
中定義屬性,并通過dispatch
進行事件的分發。
vue的方法論
- 通過
state
設置元(原)數據; - 通過
getters
設置訪問元數據的屬性(function),一般這里的屬性是邏輯是直接獲取原屬性,不再做其他的操作; - 通過
mutations
設置改變元數據的屬性(function),并且約定這里的方法都是同步適宜的。 - 通過
actions
設置改變元數據的異步方法。