1. 初识vuex
1.1 vuex官网
学习任何一门计算机语言之前,去查看具有权威的官方文档是一个明智之举。
vuex官网直链
1.2 什么情况下应该使用vuex?
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。
2. 在项目中引入 vuex (以下是直接进行了功能模块划分进行的使用说明)
2.1 安装 vuex
npm install vuex
2.2 按功能进行模块划分
2.2.1 引入所有模块所需的文件 – index.js
在项目文件夹 src 里,创建 store 文件夹,再在 store 里创建 index.js 文件,文件代码具体如下
import Vue from 'vue'
import Vuex from 'vuex'
// 引入功能模块 moduleA 、 moduleB
import moduleA from "./modules/moduleA.js"
import moduleB from "./modules/moduleB.js"
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
modules: {
// 按功能拆分module模块后,把所有的功能模块 挂载到 总的 store 上
moduleA,
moduleB
}
})
2.2.2 按功能划分的模块A – moduleA.js
/*
* 根据功能进行拆分的功能模块一 -- moduleA
*/
import axios from 'axios'
export default {
// 命名空间必须打开,个人项目中为了保证每个模块之间的独立性,防止命名冲突产生报错的问题,选择打开
namespaced: true, //开启命名空间(防止属性名冲突)
/*
* state 相当于 vue 中的 data,存储的数据
*/
state: {
scheduleTypeEnum: [{
value: 'IPI',
description: '等额本金'
},
{
value: 'EPI',
description: '等额本息'
},
{
value: 'IOI',
description: '一次还本按频率结息'
},
{
value: 'FPI',
description: '利随本清'
},
{
value: 'UDS',
description: '用户自定义还款计划'
}
]
},
/*
*getters 相当于 computed 计算属性
*/
getters: {},
/*
* mutations 执行 同步操作
*/
mutations: {},
/*
* actions 执行 异步操作
*/
actions: {}
}
2.2.3 按功能划分的模块B – moduleB
/*
* 根据功能进行拆分的功能模块一 -- moduleB
*/
export default {
state: {},
getters: {},
mutations: {},
actions: {}
}
2.2.4 在具体的页面中的使用
此处只举例 state
<template>
<div class="page-vuexUsed">
<div>{{scheduleTypeEnum}}</div>
</div>
</template>
<script>
export default {
name: 'vuexUsed',
components: {},
data () {
return {
scheduleTypeEnum: null
}
},
computed: {
// state
getScheduleTypeEnum () {
return this.$store.state.moduleA.scheduleTypeEnum
}
},
created () { },
mounted () {
},
methods: {}
}
</script>
3. vuex在页面开发中的使用详细说明
下面state、getter、mutation、action、modules部分所需引入的完整的功能模块 moduleA.js 文件,具体代码如下:
/*
* 根据功能进行拆分的功能模块一 -- moduleA
*/
import axios from 'axios'
export default {
namespaced: true, //开启命名空间 避免属性名冲突
/*
* state 相当于 vue 中的 data,存储的数据
*/
state: {
userInfo: null,
scheduleTypeEnum: [{
value: 'IPI',
description: '等额本金'
},
{
value: 'EPI',
description: '等额本息'
},
{
value: 'IOI',
description: '一次还本按频率结息'
},
{
value: 'FPI',
description: '利随本清'
},
{
value: 'UDS',
description: '用户自定义还款计划'
}
],
personOne: "Zhang San",
productsNum: 0
},
/*
*getters 相当于 computed 计算属性
*/
getters: {
// 修改personOne(使用情形:很多页面使用到personOne,需要修改)
changePersonOne(state) {
return `hello ${state.personOne}`
}
},
/*
* mutations 执行 同步操作
*/
mutations: {
// 固值更改
changeProductsNum(state) {
state.productsNum++
},
// 传值更改
changePersonOneName(state, newName) {
state.personOne = newName.newName
}
},
/*
* actions 执行 异步操作
*/
actions: {
// 调取获取用户信息 mock接口
getUserInfo() {
axios.get("/user/userInfo").then(res => {
console.log(res.data.data, "actions -- getUserInfo")
})
}
}
}
3.1 state
<script>
import { mapState } from "vuex"
export default {
name: 'vuexUsed',
components: {},
data () {
return {
state_personOne: null,
state_productsNum: null
}
},
computed: {
/* 1. state -- 应用
获取 store 仓库中 state 中 存储的 数据
第一种方式:
直接通过 this.$store.state 获取 例:this.$store.state.moduleA.scheduleTypeEnum(官方建议此方法写到计算属性中,让代码显得优雅)
第二种方式:
引入vuex的mapState方法,再把相关的解构到methods中,用this直接调用,即可 (官方推荐使用第二种)
*/
// 例:第一种方式写在 computed 中
getScheduleTypeEnum () {
return this.$store.state.moduleA.scheduleTypeEnum
},
//注意: 按功能进行模块划分后,如下方法行不通,输出为 undefined
// XXXX 此方法错误 XXXX
// error : ...mapState(["scheduleTypeEnum"]),
// 需采用此 开启了 namespaced命名空间后的 方法 (官方建议mapState写到计算属性中,让代码显得优雅)
...mapState("moduleA", ['scheduleTypeEnum', "personOne", "productsNum"]),
},
created () { },
mounted () {
// state
this.state_personOne = this.personOne
this.state_productsNum = this.productsNum
console.log(this.getScheduleTypeEnum, "state -- getScheduleTypeEnum")
console.log(this.scheduleTypeEnum, "state -- scheduleTypeEnum")
},
methods: {
}
}
</script>
<template>
<div class="page-vuexUsed">
<div>{{scheduleTypeEnum}}</div>
<ul>
<li>state.personOne:{{state_personOne}}</li>
<li>state.personOne:{{state_productsNum}}</li>
</ul>
</div>
</template>
3.2 getter
<script>
import { mapGetters } from "vuex"
export default {
name: 'vuexUsed',
components: {},
data () {
return {
}
},
computed: {
/* 2. getters -- 应用
调用 store 仓库中 getters 中 封装的 方法
第一种方式:
直接通过 this.$store.getters 调用 例:this.$store.getters["moduleA/changePersonOne"]
第二种方式:
引入vuex的mapGetters方法,再把相关的getters解构到methods中,用this直接调用,即可 (官方推荐使用第二种)
*/
// 例:第一种方式写在 computed 中
changePersonOne1 () {
return this.$store.getters["moduleA/changePersonOne"]
},
// 解构 总store 中 moduleA里的getters方法
...mapGetters("moduleA", ['changePersonOne']),
},
created () { },
mounted () {
// getters
console.log(this.changePersonOne1, "getters -- changePersonOne1")
console.log(this.changePersonOne, "getters -- changePersonOne")
},
methods: {
}
}
</script>
<template>
<div class="page-vuexUsed"></div>
</template>
3.3 mutation
<script>
import { mapMutations } from "vuex"
export default {
name: 'vuexUsed',
components: {},
data () {
return {
state_personOne: null,
state_productsNum: null
}
},
computed: {},
created () {},
mounted () {},
methods: {
/* 3. mutation -- 应用
调用 store 仓库中 actions 中封装的 同步方法
第一种方式:(官方建议 传值修改时,传入一个对象,让代码看起来更美观)
直接通过this.$store。commit 调用 例:
固值修改方法调用: this.$store.commit("moduleA/changeProductsNum")
传值修改方法调用: this.$store.commit("moduleA/changePersonOneName",{newName:"Li Si"})
*/
// 解构 总store 中 moduleA里面的同步方法
...mapMutations("moduleA", ["changePersonOneName", "changeProductsNum"]),
change_state_personOne () {
// 直接调用 mutations 同步方法
// this.$store.commit("moduleA/changePersonOneName", { newName: "Li Si" })
// this.state_personOne = this.personOne
// 解构调用 mutations 同步方法
this.changePersonOneName({ newName: "Li Si" })
// 再把 state 中更改过后的值 赋给当前页面 data 中的数据
this.state_personOne = this.personOne
},
change_state_productsNum () {
// 直接调用 mutations 同步方法
// this.$store.commit("moduleA/changeProductsNum")
// this.state_productsNum = this.productsNum
// 解构调用 mutations 同步方法
this.changeProductsNum()
this.state_productsNum = this.productsNum
}
}
}
</script>
<template>
<div class="page-vuexUsed">
<div>{{scheduleTypeEnum}}</div>
<ul>
<li>state.personOne:{{state_personOne}}</li>
<li>state.personOne:{{state_productsNum}}</li>
<li>
<button @click="change_state_personOne">change_state_personOne</button>
<button @click="change_state_productsNum" style="margin-left:50px">change_state_productsNum</button>
</li>
</ul>
</div>
</template>
3.4 action
<script>
import { mapActions } from "vuex"
export default {
name: 'vuexUsed',
components: {},
data () {
return {}
},
computed: {},
created () { },
mounted () {
/* 4. actions -- 应用
调用 store 仓库中 actions 中 封装的 异步方法
第一种方式:
直接通过 this.$store.dispatch 调用 例:this.$store.dispatch('getUserInfo')
第二种方式:
引入vuex的mapActions方法,再把相关的actions解构到methods中,用this直接调用,即可 (官方推荐使用第二种)
*/
this.$store.dispatch('moduleA/getUserInfo')
this.getUserInfo()
},
methods: {
// 解构 总store 中 moduleA里的异步方法
...mapActions("moduleA", ["getUserInfo"]),
}
}
</script>
<template>
<div class="page-vuexUsed"></div>
</template>
3.5 module
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割。
此处因个人习惯和在大多数项目应用按功能模块进行划分的次数居多,只对按功能模块进行分隔进行说明,具体的使用可以参考本文,2.1部分。
4. 以上 在项目中引入vuex 提及的所有代码
4.1 store文件夹 (存放关于所有vuex模块数据逻辑的文件夹)
4.1.1 index.js (管理所有的module模块)
/* vuex状态管理仓库 的使用
* 按功能进行拆分成 不同的 Module模块
*/
import Vue from 'vue'
import Vuex from 'vuex'
// 引入功能模块 moduleA
import moduleA from "./modules/moduleA.js"
import moduleB from "./modules/moduleB.js"
import codeAutoData from "./codeAutoCreateData/codeAutoData.js"
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
modules: {
// 按功能拆分module模块后,把所有的功能模块 挂载到 总的 store 上
moduleA,
moduleB
}
})
4.1.2 main.js(将 store 对象挂载到vue实例上)
import Vue from 'vue';
import App from './App.vue';
// 引入 按功能模块进行划分的 vuex状态管理仓库
import store from './store/index.js'
Vue.config.productionTip = false;
(window as any).vm = new Vue({
router,
store, // 将 store 对象挂载到vue实例上
render: (h) => h(App),
}).$mount('#app');
4.1.3 moduleA.js (按功能进行拆分的模块)
/*
* 根据功能进行拆分的功能模块一 -- moduleA
*/
import axios from 'axios'
export default {
// 命名空间必须打开,否则
namespaced: true, //开启命名空间 避免属性名冲突
/*
* state 相当于 vue 中的 data,存储的数据
*/
state: {
userInfo: null,
scheduleTypeEnum: [{
value: 'IPI',
description: '等额本金'
},
{
value: 'EPI',
description: '等额本息'
},
{
value: 'IOI',
description: '一次还本按频率结息'
},
{
value: 'FPI',
description: '利随本清'
},
{
value: 'UDS',
description: '用户自定义还款计划'
}
],
personOne: "Zhang San",
productsNum: 0
},
/*
*getters 相当于 computed 计算属性
*/
getters: {
// 修改personOne(使用情形:很多页面使用到personOne,需要修改)
changePersonOne(state) {
return `hello ${state.personOne}`
}
},
/*
* mutations 执行 同步操作
*/
mutations: {
// 固值更改
changeProductsNum(state) {
state.productsNum++
},
// 传值更改
changePersonOneName(state, newName) {
state.personOne = newName.newName
}
},
/*
* actions 执行 异步操作
*/
actions: {
// 调取获取用户信息 mock接口
getUserInfo() {
axios.get("/user/userInfo").then(res => {
console.log(res.data.data, "actions -- getUserInfo")
})
}
}
}
4.1.4 moduleB.js (按功能进行拆分的模块)
/*
* 根据功能进行拆分的功能模块一 -- moduleB
*/
export default {
state: {
},
getters: {},
mutations: {
},
actions: {
}
}
4.1.5 vuexUsed.vue (具体使用vuex的文件)
<!--
* @description: vuex状态管理仓库 的使用
该功能页采用 modules模块划分 并开启了 namespaced命名空间(多个store仓库挂载到一个总的 store上),与单独一个store使用有所区别
-->
<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex"
export default {
name: 'vuexUsed',
components: {},
data () {
return {
state_personOne: null,
state_productsNum: null
}
},
computed: {
/* 1. state -- 应用
获取 store 仓库中 state 中 存储的 数据
第一种方式:
直接通过 this.$store.state 获取 例:this.$store.state.moduleA.scheduleTypeEnum(官方建议此方法写到计算属性中,让代码显得优雅)
第二种方式:
引入vuex的mapState方法,再把相关的解构到methods中,用this直接调用,即可 (官方推荐使用第二种)
*/
// 例:第一种方式写在 computed 中
getScheduleTypeEnum () {
return this.$store.state.moduleA.scheduleTypeEnum
},
//注意: 按功能进行模块划分后,如下方法行不通,输出为 undefined
// XXXX 此方法错误 XXXX
// error : ...mapState(["scheduleTypeEnum"]),
// 需采用此 开启了 namespaced命名空间后的 方法 (官方建议mapState写到计算属性中,让代码显得优雅)
...mapState("moduleA", ['scheduleTypeEnum', "personOne", "productsNum"]),
/* 2. getters -- 应用
调用 store 仓库中 getters 中 封装的 方法
第一种方式:
直接通过 this.$store.getters 调用 例:this.$store.getters["moduleA/changePersonOne"]
第二种方式:
引入vuex的mapGetters方法,再把相关的getters解构到methods中,用this直接调用,即可 (官方推荐使用第二种)
*/
// 例:第一种方式写在 computed 中
changePersonOne1 () {
return this.$store.getters["moduleA/changePersonOne"]
},
// 解构 总store 中 moduleA里的getters方法
...mapGetters("moduleA", ['changePersonOne']),
},
created () { },
mounted () {
// state
this.state_personOne = this.personOne
this.state_productsNum = this.productsNum
console.log(this.getScheduleTypeEnum, "state -- getScheduleTypeEnum")
console.log(this.scheduleTypeEnum, "state -- scheduleTypeEnum")
// getters
console.log(this.changePersonOne1, "getters -- changePersonOne1")
console.log(this.changePersonOne, "getters -- changePersonOne")
/* 4. actions -- 应用
调用 store 仓库中 actions 中 封装的 异步方法
第一种方式:
直接通过 this.$store.dispatch 调用 例:this.$store.dispatch('getUserInfo')
第二种方式:
引入vuex的mapActions方法,再把相关的actions解构到methods中,用this直接调用,即可 (官方推荐使用第二种)
*/
this.$store.dispatch('moduleA/getUserInfo')
this.getUserInfo()
},
methods: {
// 解构 总store 中 moduleA里的异步方法
...mapActions("moduleA", ["getUserInfo"]),
/* 3. mutation -- 应用
调用 store 仓库中 actions 中封装的 同步方法
第一种方式:(官方建议 传值修改时,传入一个对象,让代码看起来更美观)
直接通过this.$store。commit 调用 例:
固值修改方法调用: this.$store.commit("moduleA/changeProductsNum")
传值修改方法调用: this.$store.commit("moduleA/changePersonOneName",{newName:"Li Si"})
*/
// 解构 总store 中 moduleA里面的同步方法
...mapMutations("moduleA", ["changePersonOneName", "changeProductsNum"]),
change_state_personOne () {
// 直接调用 mutations 同步方法
// this.$store.commit("moduleA/changePersonOneName", { newName: "Li Si" })
// this.state_personOne = this.personOne
// 解构调用 mutations 同步方法
this.changePersonOneName({ newName: "Li Si" })
// 再把 state 中更改过后的值 赋给当前页面 data 中的数据
this.state_personOne = this.personOne
},
change_state_productsNum () {
// 直接调用 mutations 同步方法
// this.$store.commit("moduleA/changeProductsNum")
// this.state_productsNum = this.productsNum
// 解构调用 mutations 同步方法
this.changeProductsNum()
this.state_productsNum = this.productsNum
}
}
}
</script>
<template>
<div class="page-vuexUsed">
<div>{{scheduleTypeEnum}}</div>
<ul>
<li>state.personOne:{{state_personOne}}</li>
<li>state.personOne:{{state_productsNum}}</li>
<li>
<button @click="change_state_personOne">change_state_personOne</button>
<button @click="change_state_productsNum" style="margin-left:50px">change_state_productsNum</button>
</li>
</ul>
</div>
</template>
<style lang="less" scoped>
.page-vuexUsed {
}
</style>