一、什么是module?
背景:在Vue中State使用是單一狀態(tài)樹(shù)結(jié)構(gòu),應(yīng)該的所有的狀態(tài)都放在state里面,如果項(xiàng)目比較復(fù)雜,那state是一個(gè)很大的對(duì)象,store對(duì)象也將對(duì)變得非常大,難于管理。
module:可以讓每一個(gè)模塊擁有自己的state、mutation、action、getters,使得結(jié)構(gòu)非常清晰,方便管理。
二、怎么用module?
一般結(jié)構(gòu)
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB})
模塊內(nèi)部的數(shù)據(jù):①內(nèi)部state,模塊內(nèi)部的state是局部的,也就是模塊私有的,比如是car.js模塊state中的list數(shù)據(jù),我們要通過(guò)this.
store.state.car.carGetter的結(jié)結(jié)果是undefined,而通過(guò)this.$store.state.carGetter則可以拿到。
傳參:getters====({state(局部狀態(tài)),getters(全局getters對(duì)象),roosState(根狀態(tài))});actions====({state(局部狀態(tài)),commit,roosState(根狀態(tài))}).
三、新建一個(gè)項(xiàng)目體驗(yàn)一下,通過(guò)vue –cli新建一個(gè)項(xiàng)目, 不要忘記安裝vuex,cnpm install vuex --save
不了解的童鞋可以看我的 ----深入理解vue腳手架vue-cli文章這里詳細(xì)介紹了新建vue-cli項(xiàng)目
ps: 想了解更多vuex相關(guān)知識(shí)請(qǐng)點(diǎn)擊vuex官網(wǎng)
1, 在src 目錄下新一個(gè)login文件夾,在里面新建index.js 用于存放login 模塊的狀態(tài)。 為了簡(jiǎn)單起見(jiàn),我把模塊下的state, actions,mutations, getters 全放在index.js文件中。
先簡(jiǎn)單給它增加一個(gè)狀態(tài),userName: “sam”
const state = {
useName: "sam"
};
const mutations = {
};
const actions = {
};
const getters = {
};
// 不要忘記把state, mutations等暴露出去。
export default {
state,
mutations,
actions,
getters
}
2,在src 目錄下,再新建一個(gè) store.js 這是根store, 它通過(guò)modules 屬性引入 login模塊。
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
// 引入login 模塊
import login from "./login"
export default new Vuex.Store({
// 通過(guò)modules屬性引入login 模塊。
modules: {
login: login
}
})
3, 在main.js中引入store, 并注入到vue 根實(shí)例中。
import Vue from 'vue'
import App from './App.vue'
// 引入store
import store from "./store"
new Vue({
el: '#app',
store, // 注入到根實(shí)例中。
render: h => h(App)
})
4,在 app.vue 中通過(guò)computed屬性獲取到login下的state. 這里要注意,在沒(méi)有modules 的情況下,組件中通過(guò) this.
store.state.模塊名.屬性名,在這里是 this.$store.state.login.userName
<template>
<div id="app">
<img src="./assets/logo.png">
<h1>{{useName}}</h1>
</div>
</template>
<script>
export default {
// computed屬性,從store 中獲取狀態(tài)state,不要忘記login命名空間。
computed: {
useName: function() {
return this.$store.state.login.useName
}
}
}
</script>
組件中成功獲取到狀態(tài)。項(xiàng)目目錄和展示如下
5,通過(guò)actions, mutations 改變名字, 這就涉及到dispatch action, commit mutations, mutations 改變state.
先在login 文件夾 index.js中添加changeName action 和 change_name mutations.
const mutations = {
change_name (state, anotherName) {
state.useName = anotherName;
}
};
const actions = {
changeName ({commit},anotherName) {
commit("change_name", anotherName)
}
};
在app.vue 中添加一個(gè)按鈕:<button> change to json</button>, 點(diǎn)擊時(shí),dispatch 一個(gè) action. 那在組件中怎么dispatch actions 呢?
在模塊中,state 是被限制到模塊的命名空間下,需要命名空間才能訪(fǎng)問(wèn)。 但actions 和mutations, 其實(shí)還有 getters 卻沒(méi)有被限制,在默認(rèn)情況下,它們是注冊(cè)到全局命名空間下的,所謂的注冊(cè)到全局命名空間下,其實(shí)就是我們?cè)L問(wèn)它們的方式和原來(lái)沒(méi)有module 的時(shí)候是一樣的。比如沒(méi)有module 的時(shí)候,this.
store.dispatch(“changeName”), 組件中的getters, 也是通過(guò) this.$store.getters.module中g(shù)etters 來(lái)獲取。
<template>
<div id="app">
<img src="./assets/logo.png">
<h1>{{useName}}</h1>
<!-- 添加按鈕 -->
<div>
<button @click="changeName"> change to json</button>
</div>
</div>
</template>
<script>
export default {
// computed屬性,從store 中獲取狀態(tài)state,不要忘記login命名空間。
computed: {
useName: function() {
return this.$store.state.login.useName
}
},
methods: {
// 和沒(méi)有modules的時(shí)候一樣,同樣的方式dispatch action
changeName() {
this.$store.dispatch("changeName", "Jason")
}
}
}
</script>
6, 局部參數(shù)
雖然dispatch action和 commit mutations 可以全局使用,但是寫(xiě)在module 中的actions, mutations 和getters, 它們獲得的默認(rèn)參數(shù)卻不是全局的,都是局部的,被限定在它們所在的模塊中的。比如mutations和getters 會(huì)獲得state 作為第一個(gè)默認(rèn)參數(shù),這個(gè)state參數(shù),就是限定在mutations 和getters 所在模塊的state對(duì)象,login 文件夾下的mutations 和getters 只會(huì)獲取到當(dāng)前index.js 中的 state 作為參數(shù) 。 actions 會(huì)獲得一個(gè)context 對(duì)象作為參數(shù),這個(gè)context 對(duì)象就是當(dāng)前module 的實(shí)例,module 相當(dāng)于一個(gè)小store.
那么怎樣才能獲取到根store 中的state 和 getters 呢? Vuex 提供了 rootState, rootGetters 作為module 中 getters 中默認(rèn)參數(shù), actions中context 對(duì)象,也會(huì)多了兩個(gè)屬性,context.getters, context. rootState, 這些全局的默認(rèn)參數(shù),都排在局部參數(shù)的后面。
我們?cè)趕tore.js中添加 state, getters:
export default new Vuex.Store({
// 通過(guò)modules屬性引入login 模塊。
modules: {
login: login
},
// 新增state, getters
state: {
job: "web"
},
getters: {
jobTitle (state){
return state.job + "developer"
}
}
})
login 目錄下的 index.js
const actions = {
// actions 中的context參數(shù)對(duì)象多了 rootState 參數(shù)
changeName ({commit, rootState},anotherName) {
if(rootState.job =="web") {
commit("change_name", anotherName)
}
}
};
const getters = {
// getters 獲取到 rootState, rootGetters 作為參數(shù)。
// rootState和 rootGetter參數(shù)順序不要寫(xiě)反,一定是state在前,getter在后面,這是vuex的默認(rèn)參數(shù)傳遞順序, 可以打印出來(lái)看一下。
localJobTitle (state,getters,rootState,rootGetters) {
console.log(rootState);
console.log(rootGetters);
return rootGetters.jobTitle + " aka " + rootState.job
}
};
app.vue 增加h2 展示 loacaJobTitle, 這個(gè)同時(shí)證明了getters 也是被注冊(cè)到全局中的。
<template>
<div id="app">
<img src="./assets/logo.png">
<h1>{{useName}}</h1>
<!-- 增加h2 展示 localJobTitle -->
<h2>{{localJobTitle}}</h2>
<!-- 添加按鈕 -->
<div>
<button @click="changeName"> change to json</button>
</div>
</div>
</template>
<script>
import {mapActions, mapState,mapGetters} from "vuex";
export default {
// computed屬性,從store 中獲取狀態(tài)state,不要忘記login命名空間。
computed: {
...mapState({
useName: state => state.login.useName
}),
// mapGeter 直接獲得全局注冊(cè)的getters
...mapGetters(["localJobTitle"])
},
methods: {
changeName() {
this.$store.dispatch("changeName", "Jason")
}
}
}
</script>
7, 其實(shí)actions, mutations, getters, 也可以限定在當(dāng)前模塊的命名空間中。只要給我們的模塊加一個(gè)namespaced 屬性:
const state = {
useName: "sam"
};
const mutations = {
change_name (state, anotherName) {
state.useName = anotherName;
}
};
const actions = {
changeName ({commit, rootState},anotherName) {
if(rootState.job =="web") {
commit("change_name", anotherName)
}
},
alertName({state}) {
alert(state.useName)
}
};
const getters = {
localJobTitle (state,getters,rootState,rootGetters) {
return rootGetters.jobTitle + " aka " + rootState.job
}
};
// namespaced 屬性,限定命名空間
export default {
namespaced:true,
state,
mutations,
actions,
getters
}
當(dāng)所有的actions, mutations, getters 都被限定到模塊的命名空間下,我們dispatch actions, commit mutations 都需要用到命名空間。如 dispacth("changeName"), 就要變成 dispatch("login/changeName"); getters.localJobTitle 就要變成 getters["login/localJobTitle"]
app.vue 如下:
<template>
<div id="app">
<img src="./assets/logo.png">
<h1 @click ="alertName">{{useName}}</h1>
<!-- 增加h2 展示 localJobTitle -->
<h2>{{localJobTitle}}</h2>
<!-- 添加按鈕 -->
<div>
<button @click="changeName"> change to json</button>
</div>
</div>
</template>
<script>
import {mapActions, mapState,mapGetters} from "vuex";
export default {
// computed屬性,從store 中獲取狀態(tài)state,不要忘記login命名空間。
computed: {
...mapState("login",{
useName: state => state.useName
}),
localJobTitle() {
return this.$store.getters["login/localJobTitle"]
}
},
methods: {
changeName() {
this.$store.dispatch("login/changeName", "Jason")
},
alertName() {
this.$store.dispatch("login/alertName")
}
}
}
</script>
有了命名空間之后,mapState, mapGetters, mapActions 函數(shù)也都有了一個(gè)參數(shù),用于限定命名空間,每二個(gè)參數(shù)對(duì)象或數(shù)組中的屬性,都映射到了當(dāng)前命名空間中。
<script>
import {mapActions, mapState,mapGetters} from "vuex";
export default {
computed: {
// 對(duì)象中的state 和數(shù)組中的localJobTitle 都是和login中的參數(shù)一一對(duì)應(yīng)。
...mapState("login",{
useName: state => state.useName
}),
...mapGetters("login", ["localJobTitle"])
},
methods: {
changeName() {
this.$store.dispatch("login/changeName", "Jason")
},
...mapActions('login', ['alertName'])
}
}
</script>