VueX
是適用於在Vue
項目開發時使用的狀態管理工具。Vue
爲這些被多個組件頻繁使用的值提供了一個統一管理的工具——VueX
。在具備VueX
的Vue
項目中,咱們只須要把這些值定義在VueX
中,便可在整個Vue
項目的組件中使用。javascript
npm安裝vue
npm i vuex -s
複製代碼
在項目的根目錄下新增一個store文件夾,在該文件夾內建立index.jsjava
此時項目的src
文件夾是這樣的ios
│ App.vue
│ main.js
│
├─assets
│ logo.png
│
├─components
│ HelloWorld.vue
│
├─router
│ index.js
│
└─store
index.js
複製代碼
在store.js文件中,引入vuex而且使用vuex,這裏注意變量名是大寫Vue和Vuexgit
//store.js
import Vue from 'vue'
import Vuex from 'vuex'
//掛載Vuex
Vue.use(Vuex)
//建立VueX對象
const store = new Vuex.Store({
state:{
//存放的鍵值對就是所要管理的狀態
name:'helloVueX'
}
})
export default store
複製代碼
將store掛載到當前項目的Vue實例當中去es6
//main.js
import store from './store'
new Vue({
el: '#app',
router,
store, // 和router同樣,將咱們建立的Vuex實例掛載到這個vue實例中
render: h => h(App)
})
複製代碼
在組件中使用Vuexgithub
例如在App.vue
中,咱們要將state
中定義的name
拿來在h1標籤
中顯示vuex
<template>
<div id='app'> name: <h1>{{ $store.state.name }}</h1> </div>
</template>
複製代碼
或者要在組件方法中使用npm
methods:{
add(){
console.log(this.$store.state.name)
}
},
複製代碼
具體的使用方法下面會詳細介紹axios
注意:vuex
的出現是爲了解決組件間的通訊問題,若是某個操做或者數據不涉及到公共操做,只是單一組件操做,不要把這些狀態值或者function
存儲到vuex
中,由於vuex
會把自身掛載到全部組件上,無論當前組件是否用到裏面的東西,所以這事實上確定增長了性能的損耗的.
vuex
中,有默認的五種基本的對象:
state
的計算屬性。store
的子模塊若是項目中的狀態和方法過多,index.js
文件看起來就會很臃腫而且很差維護,這個時候咱們就能夠把state
,getters
,mutations
,actions
拆分紅單個文件,有利於進行管理
此時目錄結構是這樣的
store
│
│
├─index.js
│
│
├─state.js
│
│
├─getters.js
│
│
├─mutations.js
│
│
└─actions.js
複製代碼
index.js
import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
Vue.use(Vuex);
export default new Vuex.Store({
state,
mutations,
actions,
getters,
});
複製代碼
其餘的文件中只須要export
導出便可
state.js
export default {
name:'hzw'
};
複製代碼
mutations.js
export default {
changeName(state, name) {
state.name = name;
},
};
複製代碼
getters.js
export default {
realName(state) {
return "姓名:" + state.name
},
};
複製代碼
actions.js
export default {
changeName({ commit }, name) {
return commit('changeName', name)
}
};
複製代碼
這樣看起來就更有結構感,也更易於維護了
state(vuex) ≈ data (vue)
vuex
的state
和vue
的data
有不少類似之處,都是用於存儲一些數據,或者說狀態值.這些值都將被掛載數據和dom
的雙向綁定事件,也就是當值改變的時候能夠觸發dom
的更新.
咱們在state.js
中聲明一個狀態count
,初始值爲0
,而後在組件中輸出它
// state.js
export default {
count:'0'
};
複製代碼
//組件中
<template>
<div class="hello"> <h3>{{$store.state.count}}</h3> </div>
</template>
複製代碼
結果以下圖所示
注意:雖然state
和data
有不少類似之處,但state
在使用的時候通常被掛載到子組件的computed
計算屬性上,這樣有利於state
的值發生改變的時候及時響應給子組件.若是用data
去接收$store.state
,也是能夠接收到值的,可是因爲這只是一個簡單的賦值操做,因此state
中的狀態改變的時候不能被vue
中的data
監聽到.也能夠經過watch $store
去解決這個問題,可是稍微有點麻煩.
因此,最好仍是用computed
去接收state
,以下,修改state
的方法後面會學習,這裏先進行展現.
//mutations.js
export default {
add(state, n = 0) {
return (state.count += n)
},
reduce(state, n = 0) {
return (state.count -= n)
}
}
複製代碼
//組件中
<template>
<div class="hello"> <h3>{{$store.state.count}}</h3> <div> <button @click="add(10)">增長</button> <button @click="reduce(10)">減小</button> <div>computed:{{dataCount}}</div> <div>data: {{count}}</div> </div> </div>
</template>
<script> export default { name: 'HelloWorld', data () { return { dataCount: this.$store.state.count //用data接收 } }, computed:{ count(){ return this.$store.state.count //用computed接收 } }, methods: { add(n){ this.$store.commit('add',n); }, reduce(n){ this.$store.commit('reduce',n); } } } </script>
複製代碼
而後咱們點擊增長按鈕,看看會發生什麼變化,結果以下
能夠看到,用data接收的值不能及時響應更新,用computed就能夠.
知識點:Props
,methods
,data
和computed
的初始化都是在beforeCreated
和created
之間完成的。
表面意思:mapState
是state
的輔助函數
實際做用:當一個組件須要獲取多個狀態時候,將這些狀態都聲明爲計算屬性會有些重複和冗餘。爲了解決這個問題,可使用 mapState
輔助函數幫助生成計算屬性
使用方法:先要導入這個輔助函數.
import { mapState } from 'vuex'
複製代碼
而後就能夠在computed
中使用mapState
了
用mapState
等這種輔助函數的時候,若是組件內部的命名和vuex內的命名是一致的,能夠簡寫成數組方式。
//state.js
export default {
nickname:'Simba',
age:20,
gender:'男'
};
複製代碼
//computed
computed: mapState(['nickname','age','gender'])
//上面的一句代碼就至關於下面這些 是否是簡潔了不少
computed:{
nickname(){return this.$store.state.nickname}
age(){return this.$store.state.age}
gender(){return this.$store.state.gender}
}
複製代碼
若是須要自定義一個計算屬性,須要es6
中的展開運算符:...
data(){
return{
count:14
}
}
computed: {
value(){
return "姓名:" + this.coount/7
},
...mapState(['nickname','age','gender'])
}
複製代碼
getters:對數據獲取以前的再次編譯,getters
的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被從新計算。說白了就約等於vue
的computed
,能夠像使用computed
同樣去使用getters
,固然兩者仍是有區別的.
getters
中的方法有兩個默認參數
VueX
對象中的狀態對象getters
對象,用於將getters
下的其餘getter
拿來用//state.js
export default {
name:'simba',
age:'20'
};
//getters.js
export default {
// 第一個參數是state
realName(state) {
return "姓名:" + state.name
},
// 第二個參數能夠訪問getters
nameAndAge(state, getters) {
return "年齡:" + state.age +";"+ getters.realName
}
};
複製代碼
getter
會暴露爲 store.getters
對象,咱們能夠以屬性的形式訪問這些值:
store.getters.realName// -> 姓名:simba
複製代碼
注意:getter
在經過屬性訪問時是做爲 Vue
的響應式系統的一部分緩存其中的。
咱們能夠經過讓 getters
返回一個函數,來實現給 getters
傳參。這樣在對 store
裏的數組進行查詢時很是有用。
state:{
todos:[
{
id:2,
text:'…',
done: false
}
]
},
getters: {
getTodoById: (state) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
store.getters.getTodoById(2) // -> { id: 2, text: ‘…’, done: false }
複製代碼
注意:getter
在經過方法訪問時,每次都會去進行調用,而不會緩存結果。
咱們在computed
中經過this.$store.getters.xxx
來綁定一個計算屬性
//組件中
<template>
<div class="hello"> <div> <div>{{message}}</div> <div>{{message2}}</div> </div> </div>
</template>
computed:{
message(){
return this.$store.getters.realName
},
message2(){
return this.$store.getters.nameAndAge;
}
},
複製代碼
結果以下:
mapGetters
輔助函數僅僅是將 store
中的 getter
映射到局部計算屬性:
使用方法:先要導入這個輔助函數.
import { mapGetters } from 'vuex'
複製代碼
而後就能夠在computed
中使用mapGetters
了
computed: {
...mapGetters({
message: "realName",
message2: "nameAndAge"
})
},
複製代碼
是否是簡潔了不少,若是計算屬性的名和getters的名字相同,還可使用數組簡寫形式
computed: {
...mapGetters(["realName","nameAndAge"])
},
複製代碼
mutation
是操做state
數據的方法的集合,好比對該數據的修改、增長、刪除等等。mutation
中一般存放一些同步修改狀態的方法.
注意:更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。
mutations
方法都有默認的形參:mutation([state] [,payload])
VueX
對象中的state
//state.js
export default {
name:'韓志偉'
};
//mutations.js
export default {
changeName(state, name) {
state.name = name;
},
};
複製代碼
咱們須要這樣去調用mutation
this.$store.commit('changeName','吳彥祖')
複製代碼
例如咱們在組件的methods
中修改一下name
屬性
methods: {
changeName(name){
this.$store.commit('changeName',name);
},
}
//調用changeName方法
mounted(){
this.changeName('吳彥祖')
}
複製代碼
當須要多參提交時,能夠把他們放在一個對象中
this.$store.commit('changeName',{firstName:'han',lastName:'zhiwei'})
複製代碼
也能夠用另一種傳參的方式
this.$store.commit({
type:'changeName',
payload:{
firstName:'han',
lastName:'zhiwei'
}
})
複製代碼
mapMutation
輔助函數僅僅是將 store
中的 mutation
映射到組件methods
中
使用方法:先要導入這個輔助函數.
import { mapMutation} from 'vuex'
複製代碼
而後就能夠在methods
中使用mapMutation
了
methods:{
...mapMutations({
changeName:'changeName',
})
}
複製代碼
這個代碼等同於下面這段
changeName(payLoad){
this.$store.commit('changeName',payLoad)
}
複製代碼
若是方法名和mutation名字同樣 能夠簡寫成下面這樣
methods:{
...mapMutations(['changeName'])
}
複製代碼
還可使用常量替代mutations
事件類型
在store
文件夾下面新建mutation-types.js
文件
//mutation-types.js
export const ADD_AGE = 'ADD_AGE'
//mutations.js
import * as types from './mutation-types';
export default {
[types.ADD_AGE](state, payLoad) {
state.age += payLoad.number
}
}
//組件中js部分
...mapMutations([types.ADD_AGE]),
複製代碼
可是這個不是很經常使用,知道有這個知識點就能夠了
既然講到了如何修改state
的值,順便提一下如何增刪state
中的成員
Vue.set 爲某個對象設置成員的值,若不存在則新增
Vue.set(state,"age",22)
複製代碼
Vue.delete 刪除成員
Vue.delete(state,'age')
複製代碼
因爲直接在mutation
方法中進行異步操做,可能會引發數據失效。因此提供了Actions
來專門進行異步操做,相似於axios請求,最終經過提交mutation
方法來修改state
中的值。
Actions
中的方法有兩個默認參數: Action([context ] [,payload])
dispatch
commit
state
getters
rootState
可使用es6
的解構賦值看起來更明確{ commit }
看一個例子,一秒鐘之後提交mutation
修改state
中的name
屬性
//state.js
export default {
name:'韓志偉'
};
//mutations.js
export default {
changeName(state, name) {
state.name = name;
},
};
//actions.js
export default {
asyncChangeName({ commit } ,name) {
setTimeout(() => {
commit('changeName',name);
}, 1000);
},
};
複製代碼
咱們須要這樣去調用action
this.$store.dispatch('asyncChangeName','吳彥祖')
複製代碼
例如咱們在組件的methods
中修改一下name
屬性
methods: {
changeName(name){
this.$store.dispatch('asyncChangeName',name);
},
}
//調用changeName方法
mounted(){
this.changeName('吳彥祖')
}
複製代碼
action
中也能夠調用另外一個action
//actions.js
export default {
asyncChangeName({ dispatch }) {
setTimeout(() => {
dispatch('anotherAction');
}, 1000);
},
anotherAction(){
console.log('另外一個action被調用了')
}
};
複製代碼
action
中也能夠傳入state
,以及rootState
,至於什麼是rootState
,下面學習模塊化modules
的時候就知道了
//actions.js
export default {
action({ state }) {
setTimeout(() => {
console.log(state.name)
}, 1000);
},
anotherAction({ rootState }){
setTimeout(() => {
console.log(rootState.name);
}, 1000);
}
};
複製代碼
至於actions
的傳參就與mutation
同樣了
this.$store.dispatch('changeName',{firstName:'han',lastName:'zhiwei'})
複製代碼
mapActions
輔助函數僅僅是將 store
中的 actions
映射到組件methods
中
使用方法:先要導入這個輔助函數.
import { mapActions} from 'vuex'
複製代碼
而後就能夠在methods
中使用mapActions
了
methods:{
...mapActions({
changeName:'changeName',
})
}
複製代碼
這個代碼等同於下面這段
changeName(payLoad){
this.$store.dispatch('changeName',payLoad)
}
複製代碼
若是方法名和actions名字同樣 能夠簡寫成下面這樣
methods:{
...mapActions(['changeName'])
}
複製代碼
當項目龐大,狀態很是多時,能夠採用模塊化管理模式。Vuex
容許咱們將 store
分割成模塊(module)
。每一個模塊擁有本身的 state
、mutation
、action
、getter
。
前面咱們學習瞭如何將vuex
的index.js
文件拆分紅單個文件進行管理,因此咱們依然對全部的模塊進行單文件拆分管理,目錄結構以下
store
│
├─index.js
│
├─state.js
│
├─getters.js
│
├─mutations.js
│
├─actions.js
│
└─modules
│
├─moduleA // moduleA的結構與moduleB相同
│
└─moduleB
│
├─index.js
│
├─state.js
│
├─getters.js
│
├─mutations.js
│
└─actions.js
複製代碼
1.首先根index.js中除了引入自身的state,getters,mutations,actions以外,還要引入兩個模塊的index.js並在export中導出modules
import Vue from 'vue';
import Vuex from 'vuex';
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
import moduleA from './modules/moduleA/index';
import moduleB from './modules/moduleB/index';
Vue.use(Vuex);
export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules: {
moduleA,
moduleB,
},
});
複製代碼
2.在 moduleA 的index.js中導入moduleA的state,getters,mutations,actions. moduleB同理
注意:getter
,mutation
,action
他們默認都是註冊在全局命名空間的,因此咱們默認是能夠和使用根狀態同樣去使用他們,這樣就失去了模塊化的意義,因此咱們要在模塊的index.js
中添加namespaced: true
使其成爲帶命名空間的模塊。當模塊被註冊後,它的全部 getter
、action
及 mutation
都會自動根據模塊註冊的路徑調整命名。
import state from './state';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
const moduleA = {
namespaced: true,
state: state,
getters: getters,
mutations: mutations,
actions: actions,
};
export default moduleA ;
複製代碼
3.moduleA下的state,getters,mutations,actions就和以前學習的同樣導出就能夠了
//state.js
export default {
name:'hzw'
};
//mutations.js
export default {
changeName(state, name) {
state.name = name;
},
};
//以此類推
複製代碼
state
正常寫在各自的state.js
中便可
getter
getter
的話,他會有三個參數,第一個是模塊內的 state
,第二個是 模塊內的 getters
,第三個是根節點狀態 rootState
//getters.js
export default {
nameAndAge(state, getters, rootState) {
return "年齡:" + state.age +";"+ getters.realName + "" + rootState.name
}
};
複製代碼
mutation
mutation
傳入的第一個參數也是模塊內的 state
,其實就和根狀態定義 mutation
的時候同樣
export default {
//這裏的state是模塊的局部狀態
changeName(state, name) {
state.name = name;
},
};
複製代碼
actions
action
的話,他傳入仍是隻有 context
對象,這個對象裏面的 state
屬性指模塊內的狀態,rootState
指根狀態,以下
export default {
changeName({ state,rootState }) {
console.log(state.name)
console.log(rootState .name)
}
};
複製代碼
這個要在原來狀態名前面加一個模塊名才能取到到模塊內的對象。
this.$store.state.moduleA.name;
複製代碼
輔助函數也同樣,name
前面加個模塊名
...mapState({
name: state => state.moduleA.name,
})
//簡寫
...mapState('moduleA',['name']),
複製代碼
獲取根節點的狀態仍是和之前同樣,不須要加模塊名
,也不須要加root
...mapState(['name']),
複製代碼
這個一樣要在原來狀態名前面加一個模塊名才能取到到模塊內的對象。
在獲取根狀態下的getters
不須要加模塊名
store.getters.moduleA.realName
//map函數的第一個參數也一樣須要加模塊名
computed: {
//獲取moduleA下的getters
...mapGetters("moduleA",["realName","nameAndAge"])
//獲取根狀態下的getters
...mapGetters(["realName"])
},
複製代碼
根據state
和getters
推算,在調用模塊內mutation
和action
的時候確定也須要加模塊名
在調用根狀態中的mutation
和action
的時候不須要加模塊名
methods:{
//調用模塊A下的action
...mapActions('moduleA',['changeName'])
//調用模塊A下的mutation
...mapMutation('moduleB',['changeName'])
//調用根狀態下的action
...mapActions(['changeName'])
//調用根狀態下的mutation
...mapMutation(['changeName'])
}
複製代碼
//moduleA下的actions.js
export default {
AsyncChangeName({ commit } ,name) {
setTimeout(() => {
//調用的是根狀態下的mutation
commit('changeName',name,{ root: true });
//調用的是根狀態下的action
dispatch('changeName',name,{ root: true });
}, 1000);
},
};
複製代碼
這個感受和模塊化的設計有點衝突,而且也不經常使用,知道有這個知識點便可,在聲明action
的時候,添加root:true
並將 action
的定義放到 hanler
函數中,具體以下:
//actions.js
export default {
globalAction:{
root:true,
handler({ commit } ,name) {
setTimeout(() => {
commit('changeName',name);
}, 1000);
},
}
};
複製代碼
到這裏就徹底可使用vuex
進行開發任務了!
這是我一個開源的收藏網址的項目
項目地址👉👉點擊進入,能夠直接設置爲瀏覽器主頁或者桌面快捷方式進行使用,本人在用,長期維護。
徹底開源,你們能夠隨意研究,二次開發。固然仍是十分歡迎你們點個Star⭐⭐⭐
👉👉源碼連接(gitee) 👉👉源碼連接(github)
🔊項目預覽地址(GitHub Pages):👉👉alanhzw.github.io
🔊項目預覽備用地址(本身的服務器):👉👉warbler.duwanyu.com
🔊源碼地址(gitee):👉👉gitee.com/hzw_0174/wa…
🔊源碼地址(github):👉👉github.com/alanhzw/War…
🔊個人博客:👉👉www.duwanyu.com