Vuex用来存储管理应用的所有组件状态。
state(vuex) ≈ data (vue)
Vuex 可以理解为前端数据库,用来存储数据,其中几个重要的属性:
- 属性1: state 存储所有组件的状态
- 属性2: getters 取值的唯一方法
- 属性3: mutations 唯一可以修改state值的方法
- 属性4: actions 通过提交(commit) mutation 实现异步变更状态
- 属性5:module,用来模块化Vuex
store文件夹/index.js
import Vue from "vue";
import Vuex from "vuex"
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
ytName: 'YT',
ytAge:'18'
},
getters:{
getYtName: state => state.ytName
},
mutations:{
setYtName: (state,data) => state.ytName = data
},
actions:{
acSetYtName(context, name) {
setTimeout(() => {
//延时1秒提交至mutations中的方法
context.commit("setYtName", name);
}, 1000);
}
}
})
export default store
Vuex流程图
模块化开发时:
store文件夹下
modules 文件夹下的A.js文件(根据存取的内容取名) store/modules/A.js
const state = {
handsomeMan: '相柳',
}
const mutations = {
setHandsomeMan: (state,man) => state.handsomeMan = man
}
const actions = {
acSetHandsomeMan(context, man) {
setTimeout(() => {
//延时1秒提交至mutations中的方法
context.commit("setHandsomeMan", man);
}, 2000);
}
}
export default {
// 模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名
namespaced: true,
state,
mutations,
actions
}
store/index.js:
写法一:
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
Vue.use(Vuex)
// https://webpack.js.org/guides/dependency-management/#requirecontext
/*
require.context参数介绍
require.context(directory,useSubdirectories,regExp)
directory:表示检索的目录
useSubdirectories:表示是否检索子文件夹
regExp:匹配文件的正则表达式,一般是文件名
*/
const modulesFiles = require.context('./modules', true, /\.js$/)
// you do not need `import app from './modules/app'`
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './A.js' => 'A'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({
modules,
getters
})
export default store
写法二:
import Vue from "vue";
import Vuex from "vuex";
import getters from "./getters";
import A from "./modules/A"
Vue.use(Vuex)
const store = new Vuex.Store({
// modules:{A,B},
modules:{A,B},
getters
})
export default store
配置模块时,键为命名空间名称,也就是虚拟出来的作用域,这个在组件中使用的时候,会用到,如果不单独指定命名空间名称的话,默认的命名空间名称就是导入的模块名称。
如果没有命名空间,就可能会产生冲突,产生冲突后,vuex 有合并原则可以解决问题,但是合并原则解决不了 getters 冲突的问题:
其他 4 个配置发生冲突以后,会将多个同样的数据或方法一起访问,但 getters 冲突后会报错;(所以我这里选择将getters单独提取出来,作为一个gettters.js文件)
发生冲突后,默认会先执行文件名称为 index 的代码,然后才找其他文件的代码执行 (名字叫 index 的文件,在冲突发生后,会优先执行)
store/getter.js
const getters = {
//getter为state的计算属性,获取state中的值
// 相当于store 的计算属性,返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
// Getter 接受 state 作为其第一个参数 必须要有返回值
// 通过属性的形式访问这些值 store.getters.属性名
handsomeMan: state => state.A.handsomeMan
}
export default getters
组件中使用:
<template>
<div>
<span>{{HandsomeMan}}</span>
<el-input v-model="HandsomeMan" @input="love(HandsomeMan)"></el-input>
<el-input v-model="HandsomeMan" @input="acLove(HandsomeMan)"></el-input>
</div>
</template>
<script>
export default {
name: "pageTwo",
data(){
return{
HandsomeMan:''
}
},
created() {
//获取state中的handsomeMan值
this.HandsomeMan = this.$store.getters['handsomeMan']
},
methods:{
//同步修改state
love(val){
/* 注意这里A是指A.js文件下的mutations方法setHandsomeMan
如果不写A的话,会报错:undefined mutation type */
this.$store.commit('A/setHandsomeMan',val)
},
//异步修改state
acLove(val){
/* 注意这里A是指A.js文件下actions方法setHandsomeMan
如果不写A的话,会报错:undefined atcion type */
this.$store.dispatch('A/acSetHandsomeMan',val)
}
}
}
</script>
<style scoped>
</style>
开启命名空间后(namespace:true),对应的state,getters,mutations,actions
直接使用和导入使用的写法会稍微有些不同,需要添加上空间名,参考下表:
若写项目是忘了模块中方法具体怎么写,可以先console.log(this.$store),查看store中的方法
mapstate等使用:
mapState,mapGetters在计算属性computed中使用的,将state或getter中的数据映射为计算属性computed:{ //可为state重新赋值 ...mapState({A:state =>{state.hansomeMan}}), //当模块化开发时,需要将state所在的空间名(在哪个模块下)带上 ...mapState({A: state => state.A.handsomeMan}), //数组可批量引入 ...mapState(['handsomeMan']), //当模块化开发时,需要将state所在的空间名(在哪个模块下)带上 ...mapState(['A/handsomeMan']), },
mapMutations,mapActions在方法中定义,将对应的方法映射在methods中