5 vuex
5.1 vuex是什么
- 概念:专门在 Vue 中实现集中式状态(数据)管理的一个Vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
- Github 地址: https://github.com/vuejs/vuex
5.2 什么时候用
- 多个组件依赖于同一状态
- 来自不同组件的行为需要变更同一状态
5.3 求和案例
Count.vue:-纯vue版
<template>
<div>
<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="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementOdd">当前求和为奇数再加</button>
<button @click="incrementWait">等一等再加</button>
</div>
</template>
<script>
export default {
name:'Count',
data(){
return{
n:1,//用户选择的数字
sum:0//当前的和
}
},
methods:{
increment(){
this.sum+=this.n
},
decrement(){
this.sum-=this.n
},
incrementOdd(){
if(this.sum%2){
this.sum+=this.n
}
},
incrementWait(){
setTimeout(()=>{
},500)
}
}
}
</script>
<style lang="css">
button{
margin-left: 5px;
}
</style>
5.4 vuex原理
在vscode界面,使用npm i vuex@3安装第三个版本的适用于vue2的版本
5.5 搭建环境
1.创建文件:src/store/index.js
//引入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
})
2.在 main.js 中创建vm时传入 store 配置项
//引入store
import store from './store
//创建vm
new Vue({
el:'#app',
render:h =>h(App),
store
})
5.6 基本使用
1.初始化数据、配置 actions、配置mutations,操作文件 store.js
//引入vue核心库
import Vue from 'vue
//引入Vuex
import Vuex from 'vuex
//引用Vuex
Vue.use(Vuex)
const actions ={
//响应组件中加的动作
jia(context,value){
// console.log('actions中的jia被调用了',ministore,value)
context.commit('JIA',value)
},
}
const mutations ={
//执行加
JIA(state,value){
// console.log('mutations中的JIA被调用了',state,value)
state.sum += value
}
}
//初始化数据
const state = {
sum:0
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
2.组件中读取vuex中的数据:$store.state.sum
3.组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)或$store.commit('mutations中的方法名',数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit
getters的使用
1.概念:当state中的数据需要经过加工后再使用时,可以使用getters加工
2.在 store.js 中追加 getters 配置
const getters ={
bigSum(state){
return state.sum*10
}
}
//创建并暴露store
export default new Vuex.Store({
getters
})
3.组件中读取数据:$store.getters.bigSum
5.7 四个map方法的使用
1.mapstate方法:用于帮助我们映射 state 中的数据为计算属性
computed:{
//借助mapstate生成计算属性:sum、schoo1、subject(对象写法)
...mapState({sum:'sum',school:'school',subject:'subject'})
//借助mapState生成计算属性:sum、schoo1、subject(数组写法)
...mapState(['sum','school','subject'])
},
2.mapGetters方法:用于帮助我们映射 getters 中的数据为计算属性
computed:{
//借助mapGetters生成计算属性:bigSum(对象写法)
...mapGetters({bigSum:'bigSum'})
//借助mapGetters生成计算属性:bigSum(数组写法)
..mapGetters(['bigSum'])
},
3.mapActions方法:用于帮助我们生成与 actions对话的方法,即:包含$store.dispatch(xxx)的函数
methods:{
//靠mapActions生成:incrementOdd、incrementWait(对象形式)
...mapActions({incrementOdd:'jia0dd',incrementWait:'jiaWait'})
//靠mapActions生成:incrementOdd、incrementWait(数组形式)
...mapActions(['jia0dd','jiaWait'])
}
4.mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数
methods :{
//靠mapActions生成:increment、decrement(对象形式)
...mapMutations({increment:'JIA',decrement:"JIAN'})
//靠mapMutations生成:JIA、JIAN(对象形式)
...mapMutations(['JIA','JIAN']),
}
备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
5.8 多组件共享数据
就是各个组件都能拿到state里的数据,然后用来用去了,很方便
5.9 Vuex模块化+命名空间(项目常用)
如果我们写的state,actions什么的是服务于多个种类的,比如有管加法的,有管人员的,这样放到一起很乱,所以可以把它们拆开
让代码更好维护,让多种数据分类更加明确。
使用方式:
可以都写到index.js里,也可以每个命名空间分别拆成多个js文件
const countAbout = {
namespaced:true,//开启命名空间
state:{x:1},
mutations: { ... },
actions: { ... },
getters: {...}
}
}
const personAbout = {
namespaced:true,//开启命名空间
state:{ ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
countAbout,
personAbout
}
})
1、开启命名空间后,组件中读取state数据
//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助mapState读取:
...mapState('countAbout',['sum','school','subject']),
// 前边加个参数,意思是读取countAbout 里面的 sum,school.....
2、开启命名空间后,组件中读取getters数据
//方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName'] //很奇葩
//方式二:借助mapGetters读取:
...mapGetters('countAbout',['bigSum'])
3、开启命名空间后,组件中调用dispatch
如果不写namespaced则直接写addPersonWang就可以,但是开启了命名空间,必须要加上这个名字在前边,否则会报[vuex] unknown action type: addPersonWang的错误,而且前边这个名字必须和Vuex.Store({})配置项中的名字一致。
//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions:
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
4、开启命名空间后,组件中调用commit
//方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
完整代码:
1、index.js
//引入Vue
import Vue from 'vue';
//引入Vuex
import Vuex from 'vuex';//引入插件并使用插件
Vue.use(Vuex);
//关于计数的相关配置
import countAbout from './Count'
//关于人员的相关配置
import personAbout from './Person'
//创建并导出store
export default new Vuex.Store({
modules: {
countAbout: countAbout,
personAbout //重名简写
}
});
2、Count.js
export default {
namespaced: true,
state: {
sum: 0, //初始化数据
school: '杭州',
subject: '前端',
},
getters: {
bigSum(state) {
return state.sum * 10;
}
},
actions: {
oddAdd(context, value) {
//第一个参数是浓缩版的$store,方便你在这里调用commit把东西给mutations
//第二个参数是传过来的数据
context.commit('JIA', value);
},
waitAdd(context, value) {
setTimeout(() => {
context.commit('JIA', value);
}, 1000);
},
},
mutations: {
JIA(state, value) {
//第一个参数是state对象,第二个参数是传过来的数据
console.log('mutations中的JIA被调用了 ', state, value);
state.sum += value;
},
JIAN(state, value) {
state.sum -= value;
},
}
}
3、Count.vue
<template>
<div>
<h1>当前求和为:{{ sum }}</h1>
<h2>当前求和放大十倍后为:{{ bigSum }}</h2>
<h3>我在{{ school }}学习{{ subject }}</h3>
<select v-model.number="addnum">
<option value="1" checked>1</option><!-- 不写冒号就是字符串但可以v-model.number -->
<option value="2">2</option> <!-- 不写冒号就是字符串但可以v-model.number -->
<option value="3">3</option> <!-- 不写冒号就是字符串但可以v-model.number -->
</select>
<button @click="JIA(addnum)">+</button>
<button @click="JIAN(addnum)">-</button>
<button @click="oddAdd(addnum)">当前求和为奇数再加</button>
<button @click="waitAdd(addnum)">等1秒再加</button>
<h2 style="color:red">Count里边读personList</h2>
<ul style="color:red">
<li v-for="p in personList" :key="p.id">{{ p.name }}</li>
</ul>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex';
export default {
name: 'Count',
data() {
return {
addnum: 1
}
},
computed: {
personList() {
return this.$store.state.personAbout.personList;
},
...mapState('countAbout', ['sum', 'school', 'subject']),
...mapGetters('countAbout', { bigSum: 'bigSum' }),
},
methods: {
...mapMutations('countAbout', ['JIA', 'JIAN']),
...mapActions('countAbout', { oddAdd: 'oddAdd', waitAdd: 'waitAdd' }),
},
mounted() {
console.log(this.$store)
}
};
</script>
4、Person.js
import axios from 'axios';
import { nanoid } from 'nanoid';
export default {
namespaced: true,
state: {
personList: [
{ id: 1, name: 'zzy' }
]
},
getters: {
firstPersonName(state) {
return state.personList[0].name;
}
},
actions: {
addPersonHan(context, value) {
if (value.name.indexOf('韩') === 0) {
context.commit('ADD_PERSON', value);
} else {
alert('添加的人不姓韩!');
}
},
//发送ajax请求拿到名字
addPersonServer(context) {
axios.get('http://api.uixsj.cn/hitokoto/get?type=social').then(
response => {
context.commit('ADD_PERSON', { id: nanoid(), name: response.data });
},
error => {
console.log(error.message);
}
)
}
},
mutations: {
ADD_PERSON(state, value) {
state.personList.unshift(value);
}
}
}
5、Person.vue
<template>
<div>
<h2>Person里边读personList</h2>
<input type="text" placeholder="请输入名字" v-model="name">
<button @click="addPerson">添加</button>
<button @click="addPersonHan">添加一个姓韩的人</button>
<button @click="addPersonServer">随机添加一个名字</button>
<h2>第一个人的名字:{{ firstPersonName }}</h2>
<ul>
<li v-for="p in personList" :key="p.id">{{ p }}</li>
</ul>
<h2 style="color:red">Person里读sum:{{ add }}</h2>
</div>
</template>
<script>
import { nanoid } from 'nanoid';
export default {
name: 'Person',
data() {
return {
name: ''
}
},
computed: {
personList() {
return this.$store.state.personAbout.personList;
},
add() {
return this.$store.state.countAbout.sum;
},
firstPersonName() {
return this.$store.getters['personAbout/firstPersonName'];
}
},
methods: {
addPerson() {
const personObj = { id: nanoid(), name: this.name };
this.$store.commit('personAbout/ADD_PERSON', personObj);
this.name = ''; //添加完了输入框置空
},
addPersonHan() {
const personObj = { id: nanoid(), name: this.name };
this.$store.dispatch('personAbout/addPersonHan', personObj);
},
addPersonServer() {
this.$store.dispatch('personAbout/addPersonServer');
}
},
};
</script>
注意:只有指定相应的模块名才能找到对应的数据和方法(前提是模块开启了命名空间)
其中的部分笔记引用下面的文章
Vue2(十二):Vuex环境搭建、Vuex工作原理、几个配置项、多组件共享数据、Vuex模块化_vue2 yarn安装vuex-CSDN博客