当用Vue CLI 3初始化一个Vue的项目之后,关于Vuex的内容,默认是写在 src/store.js 文件中的。
所以,我们可以对Vuex进行分层,使不同的模块区分开来。
1.改造项目
原目录是:
src/store.js
更改后的目录:
src
-- store
-- modules
-- cart.js // 购物车
-- product.js // 商品列表
-- xxx.js // 其他的,可以是 user.js,用户管理
-- index.js // 将原来的src/store.js移动到store目录,并重命名为 index.js
-- mutation-types.js // 存储一些变量的名字
2.Vuex的modules 和 namespaced
namespaced是命名空间的意思。
先建立一些变量:
mutation-types.js:
// api的列表
export const GET_PRODUCT_LIST = 'GET_PRODUCT_LIST'; // 获取商品列表
先编写两个模块:
cart.js:
// 为了防止cart.js 和product.js 中的actions相互冲突,
// 需要引入一个命名空间的概念,这样cart.js 和 product.js 中的都有用
export default {
state: {
carts:[]
},
actions: {
}
}
product.js:
import * as types from '../mutation-types';
export default {
namespaced: true,
state: {
products: []
},
actions: {
// [types.GET_PRODUCT_LIST]的意思是当前变量去取值
// 相当于 getProductList(){}
[types.GET_PRODUCT_LIST]({ commit}, payload){
console.log('xxxx');
}
}
}
3.在 src/store/index.js
src/store/index.js:
import Vue from 'vue'
import Vuex from 'vuex'
import cart from './modules/cart' // 引入其他分层的模块
import product from './modules/product'
Vue.use(Vuex)
export default new Vuex.Store({
// 如果需要引入模块中的状态,需要用到 modules
modules: {
cart,
product
},
state: {
// xxx
},
mutations: {
},
actions: {
}
})
4. 在组件中触发actions中的方法
在Home.vue组件中,去触发actions中的方法。
一般在actions里面,去请求后台接口。也就是说,把请求接口的方法,写在actions里面。然后在组件中去触发。
(1)第一种触发actions的方式:使用this.$store.dispatch方法
Home.vue:
<template>
<div class="home">
商品页
</div>
</template>
<script>
import * as types from '../store/mutation-types'
export default {
mounted(){
// 1.第一种触发actions的方式:使用this.$store.dispatch方法
// 触发actions
// 'product/' + types.GET_PRODUCT_LIST是指定product.js模块下的actions方法
this.$store.dispatch('product/'+ types.GET_PRODUCT_LIST)
}
}
</script>
(2) 第二种触发actions的方式:使用 mapActions
Home.vue:
<template>
<div class="home">
商品页
</div>
</template>
<script>
import { mapActions } from 'vuex'
import * as types from '../store/mutation-types'
export default {
methods: {
// 'product' 指的是product.js 这个模块
// [type.GET_PRODUCT_LIST] 指的是变量取值
...mapActions('product', [types.GET_PRODUCT_LIST])
},
mounted(){
// 2.第二种触发actions的方式:使用 mapActions
this[types.GET_PRODUCT_LIST]()
}
}
</script>
(3)第三种方法:createNamespaceHelpers,创建命名空间的帮助方法
Home.vue:
<template>
<div class="home">
商品页
</div>
</template>
<script>
import { createNamespacedHelpers } from 'vuex'
let { mapActions } = createNamespacedHelpers('product') // 创建product的命名空间
import * as types from '../store/mutation-types'
export default {
methods: {
// 配合createNamespacedHelpers帮助方法使用
// 已经指定命名空间,不需要在...mapActions()中指定
...mapActions([types.GET_PRODUCT_LIST])
},
mounted(){
// 2.第二种触发actions的方式:使用 mapActions
this[types.GET_PRODUCT_LIST]()
}
}
</script>
5. getters
getters,类似于computed
state和getters都属于 Vuex的属性。
比如,我们要把state状态的数据进行一次映射或者筛选,再把这个结果重新计算并提供组件使用。举个例子:
store.js:
state: {
arr: [
{id: 1, name: 'iissoft',score: 80},
{id: 2, name: 'steven', score:60},
{id: 3, name: 'jerry', score:90}
]
},
getters: {
arrList: function (state) { //这里我们对状态进行映射,进行重新计算
return state.arr.map(function(item){
return item.score >= 60 ? '及格' : '不及格';
})
}
}
此时,getters会暴露一个store.getters 对象,我们就可以在任何组件中使用 this.$store.getters.xxx来绑定数据。
在组件中调取getters中的数据。 header.vue:
<template>
<div>
<ul>
<li v-for="item in arrList">{{item}}</li>
</ul>
</div>
</template>
<script>
export default {
computed: {
arrList: function (){
return this.$store.getters.arrList; //通过store.getters对象来访问
}
}
}
</script>
另一种方式,来调取getters中的数据。
Vuex给我们提供了另一个方法mapGetters。
store.js:
state: {
arr: [ //状态
{id: 1, name: 'iissoft', score: 80 },
{id: 2, name: 'steven', score: 60},
{id: 3, name: 'jerry', score: 90}
]
},
getters: { //这里我们使用es6新语法箭头函数
arrList: state => state.arr.map(item => item.score >= 60 ? '及格':'不及格')
}
在组件中使用 mapGetters来调取 getters中的数据。
结合 ...对象运算符来合并我们组件的本地计算属性。
header.vue:
<template>
<div>
<ul>
<li v-for="item in arrList">{{item}}</li>
</ul>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['arrList'])
}
}
</script>
最后如果我们想给getters属性起个别名,我们可以通过对象的形式:
<template>
<div>
<ul>
<li v-for="item in newArr">{{item}}</li>
</ul>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters({
newArr: 'arrList' //给getters属性arrList起个别名newArr
})
}
}
</script>
6. 在mutation里面去更改状态
(1) 首先在 mutation-types.js 中去编写变量名
mutation-types.js:
// actions的变量名
// 得到短信验证码
export const DO_GET_VERIFY_CODE = 'DO_GET_VERIFY_CODE'
// mutations的变量名
// 更改公共状态codeValue
export const SET_CODE_VALUE = 'SET_CODE_VALUE'
(2) 然后去分层的模块中,去编写 actions 和 mutations 中的方法
modules/verifyCode.js:
// 引入变量名
import * as types from '../mutation-types'
// 引入接口方法
import { getVerifyCode } from '../../api/verifyCode/verifyCode'
const verifyCode = {
state: {
codeValue: '1234'
},
// 类似于computed
// getters: {},
mutations: {
// 在mutations 里面去更改状态
[types.SET_CODE_VALUE] (state, { data }) {
state.codeValue = data // 更改
}
},
//一般在actions中,去编写使用接口的方法
//然后,在组件中去调用 actions 中的方法
//通过this.$store.dispatch() 方法去调用
//如果不用this.$store.dispatch()去调用
//可以使用 mapActions 去调用
actions: {
// toGetVerifyCode ({ commit }, payload) {
// // 去使用api的接口方法
// }
// [types.DO_GET_VERIFY_CODE]的意思是当前变量去取值
// 相当于 doGetVerifyCode(){}
// [types.DO_GET_VERIFY_CODE] ({ commit }, payload) {
// console.log('xxx')
// }
[types.DO_GET_VERIFY_CODE] ({ commit, state }, payload) {
console.log('xxx')
getVerifyCode().then(data => {
console.log(data.data)
console.log(data.data.data)
// 提交给mutations的方法
commit('SET_CODE_VALUE', { data: data.data.code })
})
}
},
// namespaced: {}
namespaced: true
}
export default verifyCode
7. 统一使用 [types.DO_GET_VERIFY_CODE] 这种写法
在 Vuex 中,以及组件中,都可以使用 [types.DO_GET_VERIFY_CODE] 这种写法。
7.1 在Vuex中
(1) 首先在 mutation-types.js 中去编写变量名
mutation-types.js:
// actions的变量名
// 得到短信验证码
export const DO_GET_VERIFY_CODE = 'DO_GET_VERIFY_CODE'
// mutations的变量名
// 更改公共状态codeValue
export const SET_CODE_VALUE = 'SET_CODE_VALUE'
(2) 然后去分层的模块中,去编写 actions 和 mutations 中的方法
modules/verifyCode.js:
// 引入变量名
import * as types from '../mutation-types'
// 引入接口方法
import { getVerifyCode } from '../../api/verifyCode/verifyCode'
const verifyCode = {
state: {
codeValue: '1234'
},
// 类似于computed
// getters: {},
mutations: {
// 在mutations 里面去更改状态
[types.SET_CODE_VALUE] (state, { data }) {
state.codeValue = data // 更改
}
},
//一般在actions中,去编写使用接口的方法
//然后,在组件中去调用 actions 中的方法
//通过this.$store.dispatch() 方法去调用
//如果不用this.$store.dispatch()去调用
//可以使用 mapActions 去调用
actions: {
// toGetVerifyCode ({ commit }, payload) {
// // 去使用api的接口方法
// }
// [types.DO_GET_VERIFY_CODE]的意思是当前变量去取值
// 相当于 doGetVerifyCode(){}
// [types.DO_GET_VERIFY_CODE] ({ commit }, payload) {
// console.log('xxx')
// }
[types.DO_GET_VERIFY_CODE] ({ commit, state }, payload) {
console.log('xxx')
getVerifyCode().then(data => {
console.log(data.data)
console.log(data.data.data)
// 提交给mutations的方法
commit('SET_CODE_VALUE', { data: data.data.code })
})
}
},
// namespaced: {}
namespaced: true
}
export default verifyCode
7.2 最后,在组件中,去调用 actions 中的方法
views/order_details/order_details.vue:
<template>
<div>
获取验证码 {{codeValue}}
</div>
</template>
<script>
// 在组件中,去触发Vuex中的actions的方法
// createNamespacedHelpers,是创建命名空间的帮助方法
import { createNamespacedHelpers } from 'vuex' // 创建verifyCode的命名空间
import * as types from '../../store/mutation-types'
// 只使用verifyCode模块中的actions 和 state
let { mapActions, mapState } = createNamespacedHelpers('verifyCode')
// import { mapActions, mapState } from 'vuex'
// import * as types from '../../store/mutation-types'
export default {
name: 'order_details',
data () {
return {
}
},
computed: {
// 获取Vuex中的公共状态的值
...mapState(['codeValue'])
},
mounted () {
this.init()
// 页面加载完的时候,去使用这个方法
// 2.第二种触发actions的方法:使用 mapActions
this[types.DO_GET_VERIFY_CODE]()
},
methods: {
// 配合createNamespacedHelpers帮助方法使用
// 已经指定命名空间,不需要在...mapActions()中指定
...mapActions([types.DO_GET_VERIFY_CODE]),
init () {
// 页面一加载,就请求网银支付的银行卡接口
// 页面一加载的时候,就去执行
this.$nextTick(() => {
console.log(1232)
console.log(this.$refs.radioGroup1)
})
}
}
}
</script>
8. 关于 getters
getters 类似于 computed。
对 state 里面的数据二次处理(对数据进行过滤筛选,类似于 filter 的作用)
在 getters 中对 Vuex 顶层数据进行过滤, 而不改动 state 里原本的数据。
const getters = {
showSidebar: state => state.showSidebar
}
在组件中去获取 getters 中的数据。
可以使用 mapGetters 。
9. 使用 createNamespacedHelpers,创建命名空间的帮助方法,的情况
views/order_details/order_details.vue:
<template>
<div>
获取验证码 {{codeValue}}
</div>
</template>
<script>
// 在组件中,去触发Vuex中的actions的方法
// createNamespacedHelpers,是创建命名空间的帮助方法
import { createNamespacedHelpers } from 'vuex' // 创建verifyCode的命名空间
import * as types from '../../store/mutation-types'
// 只使用verifyCode模块中的actions 和 state
let { mapActions, mapState } = createNamespacedHelpers('verifyCode')
export default {
name: 'order_details',
data () {
return {
}
},
computed: {
// 获取Vuex中的公共状态的值
...mapState(['codeValue'])
},
mounted () {
this.init()
// 页面加载完的时候,去使用这个方法
// 2.第二种触发actions的方法:使用 mapActions
this[types.DO_GET_VERIFY_CODE]()
},
methods: {
// 配合createNamespacedHelpers帮助方法使用
// 已经指定命名空间,不需要在...mapActions()中指定
...mapActions([types.DO_GET_VERIFY_CODE]),
init () {
// 页面一加载,就请求网银支付的银行卡接口
// 页面一加载的时候,就去执行
this.$nextTick(() => {
console.log(1232)
console.log(this.$refs.radioGroup1)
})
}
}
}
</script>
前提是在分层的模块中,加上 namespaced: true,使其成为带命名空间的分层的模块。
例如:
modules/verifyCode.js:
// 引入变量名
import * as types from '../mutation-types'
// 引入接口方法
import { getVerifyCode } from '../../api/verifyCode/verifyCode'
const verifyCode = {
state: {
codeValue: '1234'
},
mutations: {
//在mutations里面去更改状态
},
actions: {
//去使用api的接口方法
},
namespaced: true
}
export default verifyCode
10. 没有使用 createNamespacedHelpers,创建命名空间的帮助方法,的情况
views/order_details/order_details.vue:
<template>
<div>
获取验证码 {{codeValue}}
</div>
</template>
<script>
import { mapActions, mapState } from 'vuex'
import * as types from '../../store/mutation-types'
export default {
name: 'order_details',
data () {
return {
}
},
computed: {
// 获取Vuex中的公共状态的值
...mapState(['codeValue'])
},
mounted () {
this.init()
// 页面加载完的时候,去使用这个方法
// 2.第二种触发actions的方法:使用 mapActions
this[types.DO_GET_VERIFY_CODE]()
},
methods: {
// 没有配合createNamespacedHelpers帮助方法使用
// 需要在...mapActions()中指定
// 在辅助函数mapActions的第一参数上,填写上模块的命名空间名。
...mapActions('verifyCode', [types.DO_GET_VERIFY_CODE]),
init () {
// 页面一加载,就请求网银支付的银行卡接口
// 页面一加载的时候,就去执行
this.$nextTick(() => {
console.log(1232)
console.log(this.$refs.radioGroup1)
})
}
}
}
</script>
前提是在分层的模块中,加上 namespaced: true,使其成为带命名空间的分层的模块。
例如:
modules/verifyCode.js:
// 引入变量名
import * as types from '../mutation-types'
// 引入接口方法
import { getVerifyCode } from '../../api/verifyCode/verifyCode'
const verifyCode = {
state: {
codeValue: '1234'
},
mutations: {
//在mutations里面去更改状态
},
actions: {
//去使用api的接口方法
},
namespaced: true
}
export default verifyCode