Vuex 模块化(modules)
│
├─ 1. 为什么要分模块?
│ └─ 项目变大后,把所有状态写在一起会很难维护,所以拆成多个小模块,
│ 每个模块管自己那一块数据(比如 user 管用户,setting 管设置)。
│
├─ 2. 怎么定义一个模块?
│ ├─ 新建一个 .js 文件(例如 user.js / setting.js)
│ ├─ 里面写 state、mutations、actions、getters
│ └─ 最重要的一点:如果要让模块"独立",必须加上 namespaced: true
│ (开启命名空间,后面会反复用到)
│
├─ 3. 怎么注册模块?
│ └─ 在 store/index.js 中:
│ import 模块 → 放到 new Vuex.Store({ modules: { ... } }) 里
│
├─ 4. 模块里的四样东西,怎么在组件中使用?
│ │
│ ├─ ① 访问 state(数据)
│ │ ├─ 直接写:$store.state.模块名.属性名
│ │ │ 例:$store.state.user.userInfo.name
│ │ └─ 用 mapState 辅助函数:
│ │ ...mapState('模块名', '属性名')
│ │ 需要模块开启 namespaced: true
│ │
│ ├─ ② 访问 getters(计算属性)
│ │ ├─ 直接写:$store.getters'模块名/getter名'
│ │ │ 例:$store.getters'user/UpperCaseName'
│ │ └─ 用 mapGetters 辅助函数:
│ │ ...mapGetters('模块名', 'getter名')
│ │ 需要模块开启 namespaced: true
│ │
│ ├─ ③ 调用 mutations(同步修改 state)
│ │ ├─ 直接写:$store.commit('模块名/方法名', 参数)
│ │ │ 例:$store.commit('user/setUser', newInfo)
│ │ └─ 用 mapMutations 辅助函数:
│ │ ...mapMutations('模块名', '方法名')
│ │ 需要模块开启 namespaced: true
│ │
│ └─ ④ 调用 actions(可以包含异步,再调用 mutation)
│ ├─ 直接写:$store.dispatch('模块名/方法名', 参数)
│ │ 例:$store.dispatch('user/setUserSecond', newInfo)
│ └─ 用 mapActions 辅助函数:
│ ...mapActions('模块名', '方法名')
│ 需要模块开启 namespaced: true
│
└─ 5. 几个关键规律(帮你记住)
├─ 规律1:state 天生挂在模块名下,不需要 namespaced 也能用 $store.state.模块名
├─ 规律2:getters、mutations、actions 默认会注册到全局,
│ 只有开启 namespaced: true 后,才必须加"模块名/"前缀来访问。
├─ 规律3:所有的 map 辅助函数(mapState、mapGetters...),
│ 只要想从某个模块里映射,第一个参数就是模块名,第二个参数是数组,
│ 前提都是 namespaced: true。
└─ 规律4:actions 里面的 context.commit('mutation名')
在开启命名空间后,会自动调用自己模块里的 mutation,不需要写模块名。
4.在模块里使用state,mutations,actions,getters
下面把第4部分 拆成4个具体的小例子,每个例子都会给出:
-
模块里的定义(user.js)
-
组件里怎么"直接写"访问
-
组件里怎么用"辅助函数"简化
所有例子都基于一个前提:模块必须开启 namespaced: true ,否则辅助函数没法直接用 '模块名' 来映射.
准备工作:模块定义(user.js)
javascript
// store/modules/user.js
const state = {
userInfo: {
name: 'zs',
age: 18
}
}
const getters = {
// 将用户名转为大写
upperName(state) {
return state.userInfo.name.toUpperCase()
}
}
const mutations = {
// 同步更新用户信息
setUser(state, newInfo) {
state.userInfo = newInfo
}
}
const actions = {
// 异步更新用户信息(1秒后更新)
setUserAsync(context, newInfo) {
setTimeout(() => {
context.commit('setUser', newInfo)
}, 1000)
}
}
export default {
namespaced: true, // 必须开启!
state,
getters,
mutations,
actions
}
① 访问 state(数据)
目标 :在组件中拿到 userInfo 这个对象
方式一:直接写
javascript
<template>
<div>
<!-- 直接从 $store.state 里取 -->
<p>用户名:{{ $store.state.user.userInfo.name }}</p>
<p>年龄:{{ $store.state.user.userInfo.age }}</p>
</div>
</template>
方式二:用 mapState 辅助函数
javascript
<template>
<div>
<!-- 映射后可以直接用属性名 -->
<p>用户名:{{ userInfo.name }}</p>
<p>年龄:{{ userInfo.age }}</p>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
// 把 user 模块里的 userInfo 映射成当前组件的计算属性
...mapState('user', ['userInfo'])
}
}
</script>
② 访问 getters(计算属性)
目标 :在组件中拿到用户名的大写形式 upperName。
方式一:直接写
注意写法:$store.getters['模块名/属性名'],这里用的是方括号,因为里面有斜杠。
javascript
<template>
<div>
用户名大写:{{ $store.getters['user/upperName'] }}
</div>
</template>
方式二:用 mapGetters 辅助函数
javascript
<template>
<div>
用户名大写:{{ upperName }}
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters('user', ['upperName'])
}
}
</script>
③ 调用 mutations(同步修改 state)
目标 :通过点击按钮,把用户信息改成 { name: 'xiaowang', age: 25 }。
方式一:直接写
javascript
<template>
<div>
<button @click="changeUser">修改用户信息</button>
</div>
</template>
<script>
export default {
methods: {
changeUser() {
// 直接 commit,注意格式:'模块名/方法名'
this.$store.commit('user/setUser', {
name: 'xiaowang',
age: 25
})
}
}
}
</script>
方式二:用 mapMutations 辅助函数
点击按钮时,直接调用 this.setUser(参数) 即可,方法和参数都更简洁
javascript
<template>
<div>
<button @click="setUser({ name: 'xiaowang', age: 25 })">
修改用户信息
</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
methods: {
// 把 user 模块里的 setUser 映射成本地方法
...mapMutations('user', ['setUser'])
}
}
</script>
④ 调用 actions(异步操作,再调用 mutation)
目标:点击按钮后,延迟1秒再更新用户信息。
方式一:直接写
javascript
<template>
<div>
<button @click="asyncChangeUser">异步修改用户信息</button>
</div>
</template>
<script>
export default {
methods: {
asyncChangeUser() {
this.$store.dispatch('user/setUserAsync', {
name: 'xiaohong',
age: 28
})
}
}
}
</script>
方式二:用 mapActions 辅助函数
javascript
<template>
<div>
<button @click="setUserAsync({ name: 'xiaohong', age: 28 })">
异步修改用户信息
</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('user', ['setUserAsync'])
}
}
</script>
| 要操作的 | 直接写法(模板/方法里写) | 辅助函数映射(需要 namespaced: true) |
|---|---|---|
| state | $store.state.user.xxx |
...mapState('user', ['xxx']) |
| getters | $store.getters['user/xxx'] |
...mapGetters('user', ['xxx']) |
| mutation | $store.commit('user/xxx', 参数) |
...mapMutations('user', ['xxx']) |
| action | $store.dispatch('user/xxx', 参数) |
...mapActions('user', ['xxx']) |
只要把这张表和上面的例子对着看,就会发现规律都是一样的:
"模块名" + "/" + "具体名称" ,然后辅助函数就是 ...mapXxx('模块名', [名称])