vuex 的详细使用
一、安装 vuex
npm i vuex@3
vue2 使用vuex3,vue3 使用 vuex4
二、搭建 vuex 环境
1. 项目根目录创建 store 文件夹,里面创建 index.js
文件
// 该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
// 引入 Vuex
import Vuex from 'vuex'
// 使用 Vuex 插件
Vue.use(Vuex)
// 准备actions--用于响应组件中的动作
const actions = {}
// 准备mutations--用于操作数据(state)
const mutations = {}
// 准备state--用于存储数据
const state = {}
// 创建并暴露 store
export default new Vuex.Store({
actions,
mutations,
state,
})
2. main.js 做如下配置
import Vue from 'vue'
import App from './App.vue'
// 引入 store
import store from '../store'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
// 传入 store 配置项
store,
}).$mount('#app')
3. 验证一下
在 Vue.vue组件中进行验证
mounted(){
console.log(this);
}
说明基本配置已经成功
三、vuex 案例
1. 拿值
在 state 先存数据 sum
// state--用于存储数据
const state = {
sum: 0 // 当前的和
}
然后在 App.vue 组件里拿值
<h3>结果: {{$store.state.sum}}</h3>
2. 进行传参加法运算
// 准备actions--用于响应组件中的动作
const actions = {
add(context,value){
context.commit('ADD',value)
}
}
// 准备mutations--用于操作数据(state)
const mutations = {
ADD(state,value){
state.sum += value
}
}
// 准备state--用于存储数据
const state = {
sum: 0 // 当前的和
}
add(context,value){} 第一个参数表示上下文,可拿到你想要的值如 state 里的值等,第二个参数表示 传过来的参数
为了区分 actions 和 mutations ,mutations 最好使用大写
- actions相当于服务员,mutations相当于后厨
- actions可以做一些逻辑判断,相当于服务员要询问要不要辣,要不要香菜啥的
- 然后再通过 mutations 对 state 里的数据进行相关的操作
在 App.vue 中
<template>
<div>
<h3>结果: {{$store.state.sum}}</h3>
<button @click="add">+{{n}}</button>
</div>
</template>
<script>
export default {
data(){
return{
// 每次相加的数
n: 1
}
},
methods: {
add(){
this.$store.dispatch('add',this.n)
}
}
}
</script>
如果 actions 中的方法不需要做一些逻辑判断,可以直接 跳到 mutations,如上面进行加法的运算
在App.vue中更改如下
methods: {
add(){
this.$store.commit('ADD',this.n)
}
}
此时就不需要经过 actions 中的 add,而是直接使用 mutations 中的 ADD
一开始我在想,为啥不在actions中直接操作 state 呢,如果这样是不能在开发者工具(后面有说到)中看到此操作的,看本文章的第一张图就可以知道,只有mutations 中的操作才被会开发者工具查看到
3. 通过 actions 进行一些判断,只有奇数的时候才可以相加
addOdd(context,value){
if(context.state.sum % 2 ){
context.commit('ADD',value)
}
}
在 App.vue 中
<button @click="addOdd">奇数加一</button>
<script>
...
addOdd(){
this.$store.dispatch('addOdd',this.n)
}
</script>
四、开发者工具的使用
vuex 也是 vue 做出来的,所以他们公用一个开发者工具 vue.js devtools
五、getters 配置项
当需要对 state 中的数据进行一些很复杂的数据处理时,比如对一个数字又乘又除还要开根号也要实现复用等复杂的处理,就可以使用getters 配置项
简单举例:上面中的sum,我要变成十倍
// 用于将state中的数据进行加工
const getters = {
bigSum(state){
return state.sum*10
}
}
// 创建并暴露 store
export default new Vuex.Store({
...
getters,
})
state 可以理解为vue组件中的
data
getters 可以理解为 vue组件中的computed(计算属性)
在 App.vue 中
<h3>放大10倍: {{$store.getters.bigSum}}</h3>
六、mapState 与 mapGetters
假如 state 中有如下数据
// state--用于存储数据
const state = {
name: '张三',
sex: '男',
age: 18,
}
那么 App.vue 取数据时,就会有点繁琐了
<h3>姓名:{{$store.state.name}}</h3>
<h3>姓别:{{$store.state.sex}}</h3>
<h3>年龄:{{$store.state.age}}</h3>
在插值表达式中是不建议写这么长的,那我们可以使用计算属性
<h3>姓名:{{xm}}</h3>
<h3>姓别:{{xb}}</h3>
<h3>年龄:{{nl}}</h3>
<script>
...
computed:{
xm(){
return this.$store.state.name
},
xb(){
return this.$store.state.sex
},
nl(){
return this.$store.state.age
},
},
</script>
可以发现这样写重复的内容非常多,所以 vuex 就有了mapState
使用 mapState
import { mapState } from "vuex"
export default {
computed: {
// 借助mapState生成计算属性,从state中读取数据。(对象写法)
...mapState({xm: 'name', xb: 'sex', nl: 'age'})
},
}
由于mapstate 是一个对象,所以要使用展开运算符
如果计算属性的名字和state中的命名一致时简写如下
// 借助mapState生成计算属性,从state中读取数据。(数组写法)
...mapState(['name', 'sex', 'age'])
同理,getters 也有 mapGetters
举例:上面我们有一个getters 里面有一个 bigSum,App.vue
中我们可以改成如下:
import { mapState, mapGetters } from "vuex"
export default {
computed: {
// 借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
...mapGetters(['bigSum'])
},
}
七、mapActions和mapMutations
通过第六节学的mapState 与 mapGetters,大概也知道mapActions和mapMutations的作用了吧
前面我们对state中的sum加一时,使用的是
<button @click="add">+{{n}}</button>
<script>
data() {
return {
// 每次相加的数
n: 1
};
},
methods: {
add() {
this.$store.commit("ADD", this.n);
},
}
</script>
使用mapMutations时:
<button @click="add(n)">+{{n}}</button>
<script>
import { mapState, mapGetters, mapMutations} from "vuex"
...
methods: {
// 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(对象写法)
...mapMutations({add: 'ADD'}),
}
</script>
如果方法名和mutations里面的一样也可以使用数组的方法,这里就不举例了
记得在方法里面进行传参
mapActions 你肯定也是会的啦,老样子看一下以前的写法
<button @click="addOdd">奇数加一</button>
...
addOdd() {
this.$store.dispatch("addOdd", this.n);
}
使用 mapActions
<button @click="addOdd(n)">奇数加一</button>
<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex"
...
methods: {
// 借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(数组写法)
...mapActions(['addOdd'])
}
</script>
八、多组件数据共享
其实跟上面的第七没啥区别,下面简单演示一下在 HelloWord.vue 使用vuex
<template>
<div>
<h3>姓名:{{name}}</h3>
<h3>姓别:{{sex}}</h3>
<h3>年龄:{{age}}</h3>
<h4>sum的值:{{sum}} 十倍:{{bigSum}}</h4>
<button @click="addOdd(1)">奇数加一</button>
<button @click="ADD(1)">加一</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
export default {
computed:{
...mapState(['name','sex','age','sum']),
...mapGetters(['bigSum'])
},
methods:{
...mapActions(['addOdd']),
...mapMutations(['ADD'])
}
}
</script>
九、vuex 模块化
假如我们做的系统比较大,功能很多,命名也容易冲突等,则不可能把全部代码都放到一个 .js
文件里面,应该进行分类的管理
1. 我们先在一个 .js
文件里面进行分类
// 该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
// 引入 Vuex
import Vuex from 'vuex'
// 使用 Vuex 插件
Vue.use(Vuex)
// 计数相关的配置
const countOptions = {
// 开启命名空间
namespaced: true,
actions: {
add(context, value) {
context.commit('ADD', value)
},
addOdd(context, value) {
if (context.state.sum % 2) {
context.commit('ADD', value)
}
}
},
mutations: {
ADD(state, value) {
state.sum += value
}
},
state: {
sum: 1,
},
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
// 人员信息相关的配置
const personOptions = {
// 开启命名空间
namespaced: true,
actions: {},
mutations: {},
state: {
name: '张三',
sex: '男',
age: 18,
},
getters: {}
}
// 创建并暴露 store
export default new Vuex.Store({
modules:{
countAbout:countOptions,
personAbout:personOptions
}
})
使用上面第八的 HelloWord.vue 来进行演示
<template>
<div>
<h3>姓名:{{name}}</h3>
<h3>姓别:{{sex}}</h3>
<h3>年龄:{{age}}</h3>
<h4>sum的值:{{sum}} 十倍:{{bigSum}}</h4>
<button @click="addOdd(1)">奇数加一</button>
<button @click="ADD(1)">加一</button>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
export default {
computed:{
...mapState('countAbout',['sum']), // countAbout 为js开启的命名空间,指定是谁里面的配置
...mapState('personAbout',['name','sex','age']),
...mapGetters('countAbout',['bigSum'])
},
methods:{
...mapActions('countAbout',['addOdd']),
...mapMutations('countAbout',['ADD'])
}
}
</script>
- js 文件中每一个配置都开启命名空间,就是为了后面 .vue 组件中区分每一个配置进行使用
2. 下面我们把相关的配置放在一个独立
文件里面
计算相关的放在 count.js 文件里
// 计数相关的配置
export default {
// 开启命名空间
namespaced: true,
actions: {
add(context, value) {
context.commit('ADD', value)
},
addOdd(context, value) {
if (context.state.sum % 2) {
context.commit('ADD', value)
}
}
},
mutations: {
ADD(state, value) {
state.sum += value
}
},
state: {
sum: 1,
},
getters: {
bigSum(state) {
return state.sum * 10
}
}
}
人员信息相关的配置放在person.js里
// 人员信息相关的配置
export default {
// 开启命名空间
namespaced: true,
actions: {},
mutations: {},
state: {
name: '张三',
sex: '男',
age: 18,
},
getters: {}
}
index.js文件变成
// 该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
// 引入 Vuex
import Vuex from 'vuex'
import countOptions from './count'
import personOptions from './person'
// 使用 Vuex 插件
Vue.use(Vuex)
// 创建并暴露 store
export default new Vuex.Store({
modules:{
countAbout:countOptions,
personAbout:personOptions
}
})
这样根据功能分成不同的 .js 文件,结构清晰易懂
参考资料