这里写目录标题
vuex
一 vuex是什么?
概念:专门在Vue 中实现集中式状态(数据)管理的一个Vue 插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
vuex官方地址: vuex官方地址
什么时候使用vuex?
1 多个组件依赖同一个状态
2 来自不同组件的行为需要变更统一状态
二 vuex工作原理
1 工作原理图
图中少一条线 此处vc也可以直接commit交给mutations处理
2 vuex原理分析
Backend API:后端接口
Devtools:vuex出的开发者调试工具
vuex 由三部分组成:这三部分由store(仓库)管理
1 Actions 动作:本质也是一个对象{} 当执行dispatch(动作类型,值)函数时,第二个参数值 可以通过ajax请求后端拿值 如果知道第二个参数 可以直接省略
2 Mutaitions 修改 : 本质也是一个对象{} 此对象可以拿到state
3 State数据 :本质是一个对象{} 存放数据
api及流程:
store.dispatch(分发):dispatch(“进行的动作类型(如加减)”,值(加的值2/ajax请求的值))是一个函数
store.commit(提交) :commit(“进行的动作类型(如加减)”,值(加的值2/ajax请求的值)) 交给 Mutaitions mutade(变化)更新 State中的内容 最后render渲染给组件
三 vuex环境搭建
1 npm i vuex@版本号
注意: vue2中只能用vuex的3版本 vue3中要用vuex的4版本
2 在src下新建store文件夹及index.js
注意有的人可能是新建了 一个vuex文件夹及store.js 这两种方式都行 官方推荐store下index.js这种方式
3 在index.js中创建store
index.js 代码如下:
//该文件用于创建Vuex中最为核心的store
// 引入vue
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
})
4 在main.js中引入store 并添加配置项
这样就成功搭建好了!!!
四 禹神同款案例
1 求和案例 纯vue版本
写个纯vue版 这不是有手就行吗 这个案例就不详细说了 直接上代码
AnLi.vue 组件代码:
<template>
<div class="box">
<h1>当前求和为:{{ sum }}</h1>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="add">+</button>
<button @click="jian">-</button>
<button @click="jishuadd">当前值为奇数在加</button>
<button @click="ddadd">等一等在加</button>
</div>
</template>
<script>
export default {
data() {
return {
sum: 0,
n: 1,
};
},
methods: {
add() {
this.sum += this.n;
},
jian() {
this.sum -= this.n;
},
jishuadd() {
if (this.sum % 2) {
this.sum += this.n;
}
},
ddadd() {
setTimeout(() => {
this.sum += this.n;
}, 500);
},
},
};
</script>
<style scoped>
button {
margin-left: 5px;
}
</style>
运行结果截图为:
2 求和案例 纯vuex版本(基础版本)
store下index.js代码:
//该文件用于创建Vuex中最为核心的store
// 引入vue
import Vue from "vue";
// 引入vuex
import Vuex from "vuex"
// 使用vuex插件
Vue.use(Vuex)
// 准备actions- 用于响应组件中的动作
const actions = {
// 如果没有逻辑 可以直接commit给mutations处理 以下就是没有逻辑的
// jiafa(context, val) {
// // 此处有两个参数 context有上下文的意思是一个对象 第二个参数为值
// console.log('actions中的jianfa动作被调用了', context, val);
// // 交给mutations处理
// context.commit('JIAFA', val)
// },
// jianfa(context, val) {
// context.commit('JIANFA', val)
// },
// // 逻辑写在这里就对了(ajax请求 或者if判断)
jishujiafa(context, val) {
if (context.state.sum % 2) {
context.commit('JIAFA', val)
}
},
ddjiafa(context, val) {
setTimeout(() => {
context.commit('JIAFA', val)
}, 500)
},
}
// 准备mutations-用于操作数据(state) 这里写操作数组的方法
const mutations = {
JIAFA(state, val) {
// 此处第一个参数为state数据 第二个参数为值
console.log('mutations中的JIAFA被调用了', state, val);
state.sum += val
},
JIANFA(state, val) {
state.sum -= val
}
}
// 准备state-用于存储数据
const state = {
sum: 0,
}
// 创建并且暴露store
export default new Vuex.Store({
// 传入配置项
actions, mutations, state
})
AnLi.vue代码:
<template>
<div class="box">
<h1>当前求和为:{{ $store.state.sum }}</h1>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="add">+</button>
<button @click="jian">-</button>
<button @click="jishuadd">当前值为奇数在加</button>
<button @click="ddadd">等一等在加</button>
</div>
</template>
<script>
export default {
data() {
return {
n: 1,
};
},
methods: {
add() {
// 这里直接commit交给mutations处理
this.$store.commit("JIAFA", this.n);
},
jian() {
this.$store.commit("JIANFA", this.n);
},
jishuadd() {
this.$store.dispatch("jishujiafa", this.n);
},
ddadd() {
this.$store.dispatch("ddjiafa", this.n);
},
},
};
</script>
<style scoped>
button {
margin-left: 5px;
}
</style>
运行结果:
3 多组件通信案例
组件可以直接通过$store.state.拿到vuex中state中的数据
AnLi组件代码:
<template>
<div class="box">
<h1>当前求和为:{{ sum }}</h1>
<h3>当前求和放大10倍为:{{ bigSum }}</h3>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="add(n)">+</button>
<button @click="jian(n)">-</button>
<button @click="jishuadd(n)">当前值为奇数在加</button>
<button @click="ddadd(n)">等一等在加</button>
<h4 style="color: red">AnLi1组件中的人员个数为:{{ list.length }}</h4>
</div>
</template>
<script>
// import store from "@/store";
import { mapState, mapGetters, mapActions, mapMutations } from "vuex";
export default {
data() {
return {
n: 1,
};
},
methods: {
// 程序员手写
// add() {
// // 这里直接commit交给mutations处理
// this.$store.commit("JIAFA", this.n);
// },
// jian() {
// this.$store.commit("JIANFA", this.n);
// },
// jishuadd() {
// this.$store.dispatch("jishujiafa", this.n);
// },
// ddadd() {
// this.$store.dispatch("ddjiafa", this.n);
// },
// 借助mapMutations对象生成对应的方法 方法中会调用commit去联系Mutations (注意还要在使用add方法是传参) (对象写法)
...mapMutations({ add: "JIAFA", jian: "JIANFA" }),
// 借助mapMutations对象生成对应的方法 方法中会调用commit去联系Mutations (数组写法)
//注意 方法名与 Mutations中的方法名一样
// ...mapMutations(['JIAFA','JIANFA']),
// 借助mapActions对象生成对应的方法 方法中会调用dispatch去联系mapActions (对象写法)
...mapActions({ jishuadd: "jishujiafa", ddadd: "ddjiafa" }),
// 借助mapActions对象生成对应的方法 方法中会调用dispatch去联系mapActions (数组写法)
// ...mapActions(['jishujiafa','ddjiafa']),
},
computed: {
// 方式一 程序员自己手写计算属性 简化代码
// he() {
// return this.$store.state.sum;
// },
// beishu() {
// return this.$store.getters.bigSum;
// },
// 方式二:对象写法
// ...mapState({ he: "sum" }),
// ...mapGetters({ beishu: "bigSum" }),
// 数组写法 要求计算属性名与state中的名字一样
// sum() {
// return this.$store.state.sum;
// },
// bigSum() {
// return this.$store.getters.bigSum;
// },
// 简写如下:
...mapState(["sum", "list"]),
...mapGetters(["bigSum"]),
},
};
</script>
<style scoped>
button {
margin-left: 5px;
}
</style>
AnLi1组件代码:
<template>
<div>
<h1>人员列表</h1>
<input type="text" placeholder="请输入添加人姓名" v-model="namee" />
<button @click="addname">添加</button>
<ul>
<li v-for="item in list" :key="item.id">{{ item.name }}</li>
</ul>
<h3 style="color: red">AnLi组件的求和为:{{ sum }}</h3>
</div>
</template>
<script>
// 引入nanoid
import { nanoid } from "nanoid";
export default {
data() {
return {
namee: "",
};
},
methods: {
addname() {
const listObj = { id: nanoid(), name: this.namee };
// console.log(listObj);
this.$store.commit("ADDL", listObj);
this.namee = "";
},
},
computed: {
list() {
return this.$store.state.list;
},
sum() {
return this.$store.state.sum;
},
},
};
</script>
<style>
</style>
store下index中代码:
//该文件用于创建Vuex中最为核心的store
// 引入vue
import Vue from "vue";
// 引入vuex
import Vuex from "vuex"
// 使用vuex插件
Vue.use(Vuex)
// 准备actions- 用于响应组件中的动作
const actions = {
// 如果没有逻辑 可以直接commit给mutations处理 以下就是没有逻辑的
// jiafa(context, val) {
// // 此处有两个参数 context有上下文的意思是一个对象 第二个参数为值
// console.log('actions中的jianfa动作被调用了', context, val);
// // 交给mutations处理
// context.commit('JIAFA', val)
// },
// jianfa(context, val) {
// context.commit('JIANFA', val)
// },
// // 逻辑写在这里就对了(ajax请求 或者if判断)
jishujiafa(context, val) {
if (context.state.sum % 2) {
context.commit('JIAFA', val)
}
},
ddjiafa(context, val) {
setTimeout(() => {
context.commit('JIAFA', val)
}, 500)
},
}
// 准备mutations-用于操作数据(state) 这里写操作数组的方法
const mutations = {
JIAFA(state, val) {
// 此处第一个参数为state数据 第二个参数为值
console.log('mutations中的JIAFA被调用了', state, val);
state.sum += val
},
JIANFA(state, val) {
state.sum -= val
},
ADDL(state, listObj) {
state.list.unshift(listObj)
}
}
// 准备state-用于存储数据
const state = {
sum: 0,
list: [{ id: 1, name: "小明" }],
}
// 准备getters用于将state中的数据进行加工
const getters = {
bigSum(state) {
return state.sum * 10
}
}
// 创建并且暴露store
export default new Vuex.Store({
// 传入配置项
actions, mutations, state, getters
})
实现多组件共享数据运行结果:
五 vuex开发者工具
vuex也是vue官方做的 也就是选vue开发者工具
选择vuex开发者工具
六 store中的其他配置项
1 getters配置项
state配置项和getters配置项 就相当于 data 和computed一样
用于将state中的数据进行加工
在store下inidex.js中添加配置项:
const getters = {
bigSum(state) {
return state.sum * 10
}
}
在组件中使用时:$store.getters.bigSum
index.js代码:
//该文件用于创建Vuex中最为核心的store
// 引入vue
import Vue from "vue";
// 引入vuex
import Vuex from "vuex"
// 使用vuex插件
Vue.use(Vuex)
// 准备actions- 用于响应组件中的动作
const actions = {
// 如果没有逻辑 可以直接commit给mutations处理 以下就是没有逻辑的
// jiafa(context, val) {
// // 此处有两个参数 context有上下文的意思是一个对象 第二个参数为值
// console.log('actions中的jianfa动作被调用了', context, val);
// // 交给mutations处理
// context.commit('JIAFA', val)
// },
// jianfa(context, val) {
// context.commit('JIANFA', val)
// },
// // 逻辑写在这里就对了(ajax请求 或者if判断)
jishujiafa(context, val) {
if (context.state.sum % 2) {
context.commit('JIAFA', val)
}
},
ddjiafa(context, val) {
setTimeout(() => {
context.commit('JIAFA', val)
}, 500)
},
}
// 准备mutations-用于操作数据(state) 这里写操作数组的方法
const mutations = {
JIAFA(state, val) {
// 此处第一个参数为state数据 第二个参数为值
console.log('mutations中的JIAFA被调用了', state, val);
state.sum += val
},
JIANFA(state, val) {
state.sum -= val
}
}
// 准备state-用于存储数据
const state = {
sum: 0,
}
// 准备getters用于将state中的数据进行加工
const getters = {
bigSum(state) {
return state.sum * 10
}
}
// 创建并且暴露store
export default new Vuex.Store({
// 传入配置项
actions, mutations, state, getters
})
AnLi.vue代码为:
<template>
<div class="box">
<h1>当前求和为:{{ $store.state.sum }}</h1>
<h3>当前求和放大10倍为:{{ $store.getters.bigSum }}</h3>
<select v-model.number="n">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button @click="add">+</button>
<button @click="jian">-</button>
<button @click="jishuadd">当前值为奇数在加</button>
<button @click="ddadd">等一等在加</button>
</div>
</template>
<script>
// import store from "@/store";
export default {
data() {
return {
n: 1,
};
},
methods: {
add() {
// 这里直接commit交给mutations处理
this.$store.commit("JIAFA", this.n);
},
jian() {
this.$store.commit("JIANFA", this.n);
},
jishuadd() {
this.$store.dispatch("jishujiafa", this.n);
},
ddadd() {
this.$store.dispatch("ddjiafa", this.n);
},
},
};
</script>
<style scoped>
button {
margin-left: 5px;
}
</style>
运行截图:
2 mapstate和mapgetters
mapstate (映射state)和mapgetters(映射getters)是为了简化代码的
第一种方法:程序员直接自己手写计算属性
计算属性:
computed: {
he() {
return this.$store.state.sum;
},
beishu() {
return this.$store.getters.bigSum;
},
},
使用时插值语法:
第二种方法:
利用 mapstate (映射state)和mapgetters(映射getters) 本质是两个对象
第一步先引入
import { mapState, mapGetters } from "vuex";
a:对象写法
...mapState({ he: "sum" }),
...mapGetters({ beishu: "bigSum" }),
使用时:
数组写法:要求计算属性名与state中的名字一样
...mapState(["sum"]),
...mapGetters(["bigSum"]),
使用方法:
综合对比 :
3 mapActions和mapMutations
利用mapActions和mapMutations 简化代码
1 借助mapMutations对象生成对应的方法 方法中会调用commit去联系Mutations
2借助mapActions对象生成对应的方法 方法中会调用dispatch去联系mapActions
代码如下:
methods: {
// 程序员手写
// add() {
// // 这里直接commit交给mutations处理
// this.$store.commit("JIAFA", this.n);
// },
// jian() {
// this.$store.commit("JIANFA", this.n);
// },
// jishuadd() {
// this.$store.dispatch("jishujiafa", this.n);
// },
// ddadd() {
// this.$store.dispatch("ddjiafa", this.n);
// },
// 借助mapMutations对象生成对应的方法 方法中会调用commit去联系Mutations (注意还要在使用add方法是传参) (对象写法)
...mapMutations({ add: "JIAFA", jian: "JIANFA" }),
// 借助mapMutations对象生成对应的方法 方法中会调用commit去联系Mutations (数组写法)
//注意 方法名与 Mutations中的方法名一样
// ...mapMutations(['JIAFA','JIANFA']),
// 借助mapActions对象生成对应的方法 方法中会调用dispatch去联系mapActions (对象写法)
...mapActions({ jishuadd: "jishujiafa", ddadd: "ddjiafa" }),
// 借助mapActions对象生成对应的方法 方法中会调用dispatch去联系mapActions (数组写法)
// ...mapActions(['jishujiafa','ddjiafa']),
},
七 vuex模块化
-
目的:让代码更好维护,让多种数据分类更加明确。
-
修改
store.js
const countAbout = { namespaced:true,//开启命名空间 state:{x:1}, mutations: { ... }, actions: { ... }, getters: { bigSum(state){ return state.sum * 10 } } } const personAbout = { namespaced:true,//开启命名空间 state:{ ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { countAbout, personAbout } })
-
开启命名空间后,组件中读取state数据:
//方式一:自己直接读取 this.$store.state.personAbout.list //方式二:借助mapState读取: ...mapState('countAbout',['sum','school','subject']),
-
开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取 this.$store.getters['personAbout/firstPersonName'] //方式二:借助mapGetters读取: ...mapGetters('countAbout',['bigSum'])
-
开启命名空间后,组件中调用dispatch
//方式一:自己直接dispatch this.$store.dispatch('personAbout/addPersonWang',person) //方式二:借助mapActions: ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
-
开启命名空间后,组件中调用commit
//方式一:自己直接commit this.$store.commit('personAbout/ADD_PERSON',person) //方式二:借助mapMutations: ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),