Vue2--Vuex

481 阅读3分钟

Vuex介绍与使用

Vuex的基本理解

1、概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读或写),也是一种组件间通信的方式,且适用于任意组件间通信

2、什么时候使用Vuex?

(1)多个组件依赖于同一状态

(2)来自不同组件的行为需要变更同一状态

全局事件总线只能读取兄弟组件传来的数据,如果需要实现对数据的修改需要再写一个全局事件总线用来将修改后的值返回原来的组件中;而vuex可以方便的实现多个组件对数据的读取和修改。 image.png

Vuex的工作原理

image.png

1、Actions:接收从Vue Componts传递过来的方法和数值;去后台调用相关的数值

2、Mutation:用Action传来的方法和数据,真正对数据进行加工处理。注意,所有业务逻辑(比如条件判断等)都在Action中,Mutation中只负责进行数据运算与加工。Mutations直接与Vuex的开发者工具进行对话。

3、State:将处理好的结果返回给Vue Components

注意:

1、Actions、Mutations、State是store中的三个对象,接收store的管理;

2、store提供上图中的Dispatch、Commit、Mutate、Render方法;

3、所有的组件对象都要能看到store;

搭建Vuex环境

基本步骤:

1、安装Vuex

Note:Vue2 中使用Vuex3;Vue3中使用Vuex4

npm i vuex@3

2、使用Vuex

(1)main.js

//引入vuex
import Vuex from 'vuex'
//使用插件
Vue.use(Vuex)

完成(1)后所有的组件对象上都有了$store这个对象,实现了所有组件对象都能看到store的效果

(2)新建如下文件:

image.png

3、新建store,并配置让所有组件都能看到它

  • /store/index.js
//该文件用于创建Vuex中最为核心的store

//引入vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用Vuex,注意要写在这里!!!!!
Vue.use(Vuex)
//准备actions--用于响应组件中的动作
const actions = {}
//准备mutations--用于操作数据
const mutations = {}
//准备state--用于存储数据
const state = {}

//创建并到处store
export default new Vuex.Store({
	actions:actions,
	mutations:mutations,
	state:state
})

  • main.js
//引入vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//引入插件
import vueResource from 'vue-resource'
//引入store
import store from './store/index.js'

Vue.config.productionTip = false
//使用插件
Vue.use(vueResource)

new Vue({
  render: h => h(App),
  store:store,
  beforeCreate() {
  	Vue.prototype.$but = this
  },
}).$mount('#app')


上面这样写的原因:因为js文件会先扫描出import文件执行后再去按顺序执行其他语句,所以main.js中如果写上import store from './store/index.js'会报错,因为需要先使用Vuex才能执行import store from './store/index.js'语句,而Vue.use(Vuex)会在import后执行。为了解决这个问题需要在index.js中先使用Vuex,如上面代码所示。

求和案例

纯vue版本的求和案例

1、需求:

(1)显示当前数字sum,一个下拉框可以选择要操作的数字x;

(2)点击+按钮,sum += x;

(3)点击-按钮,sum -= x;

(4)点击“当前和为奇数再加”按钮,只有再now为奇数时 sum += x;

(5)点击“等一等再加”按钮,等待0.5s再执行 sum += x;

2、实现:

  • App.vue
<template>
    <div class="container">
		<Count></Count>
	</div>
</template>

<script scoped>
	import Count from './components/Count.vue'
	export default {
		name:'App',
		components:{Count},
	}
</script>

<style>
	.container, .meishi{
		display: flex;
		justify-content: space-around;
	}
	video{
		width: 100%;
	}
	img{
		width: 100%;
	}
	h4{
		text-align: center;
	}
	
</style>

  • Count.vue
<template>
	<div>
		<h1>当前求和为:{{sum}}</h1>
		<!-- 这里加上v-model.number将n转换为number类型 -->
		<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(()=>{
					this.sum += this.n
				},500)
			},
		},
	}
</script>

<style lang="css">
	button{
		padding: 5px;
	}
</style>

3、效果:

求和案例纯vue.gif

Vuex版本的求和案例

1、需求:

(1)显示当前数字sum,一个下拉框可以选择要操作的数字x;

(2)点击+按钮,sum += x;

(3)点击-按钮,sum -= x;

(4)点击“当前和为奇数再加”按钮,只有再now为奇数时 sum += x;

(5)点击“等一等再加”按钮,等待0.5s再执行 sum += x;

2、实现:

  • App.vue
<template>
    <div>
		<Count></Count>
	</div>
</template>

<script scoped>
	import Count from './components/Count.vue'
	export default {
		name:'App',
		components:{Count},
		mounted() {
			//console.log('App',this);
		}
	}
</script>

<style>
	.container, .meishi{
		display: flex;
		justify-content: space-around;
	}
	video{
		width: 100%;
	}
	img{
		width: 100%;
	}
	h4{
		text-align: center;
	}
	
</style>

  • Count.vue
<template>
	<div>
		<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="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,//用户选择的数字
			}
		},
		methods:{
			increment(){
				this.$store.commit('JIA',this.n);
			},
			decrement(){
				this.$store.commit('JIAN',this.n);
			},
			incrementOdd(){				
				this.$store.dispatch('jiaOdd',this.n);
			},
			incrementWait(){
				this.$store.dispatch('jiaWait',this.n);
			},
		},
		mounted() {
			//console.log('Count',this)
		}
	}
</script>

<style lang="css">
	button{
		padding: 5px;
	}
</style>

  • /store/index.js
//该文件用于创建Vuex中最为核心的store

//引入vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用Vuex
Vue.use(Vuex)
//准备actions--用于响应组件中的动作
const actions = {
	// jia(context,value){
	// 	context.commit('JIA',value);
	// },
	// jian(context,value){
	// 	context.commit('JIAN',value);
	// },
	jiaWait(context,value){
		setTimeout(()=>{
			context.commit('JIA',value);
		},500);
	},
	jiaOdd(context,value){
		if(context.state.sum%2){ //注意这里必须是访问state的sum,如果直接访问sum是undefined
			context.commit('JIA',value);
		}
	},
}
//准备mutations--用于操作数据
const mutations = {
	// mutations中的方法名称一般是大写
	JIA(state,value){
		state.sum += value;
	},
	JIAN(state,value){
		state.sum -= value;
	}
}
//准备state--用于存储数据
const state = {
	sum:0,
	school:'尚硅谷',
	subject:'前端',
}

//创建并到处store
export default new Vuex.Store({
	actions:actions,
	mutations:mutations,
	state:state,
})

3、效果:与这里一样

getters配置项

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

案例

1、需求:在求和案例中追加一个条件:将sum放大10被显示出来

2、实现:需要对/store/index.js和Count.vue中进行修改

  • Count.vue
<template>
	<div>
		<h1>当前求和为:{{$store.state.sum}}</h1>
		<h1>当前求和放大十倍为:{{$store.getters.bigSum}}</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,//用户选择的数字
			}
		},
		methods:{
			increment(){
				this.$store.commit('JIA',this.n);
			},
			decrement(){
				this.$store.commit('JIAN',this.n);
			},
			incrementOdd(){				
				this.$store.dispatch('jiaOdd',this.n);
			},
			incrementWait(){
				this.$store.dispatch('jiaWait',this.n);
			},
		},
		mounted() {
			//console.log('Count',this)
		}
	}
</script>

<style lang="css">
	button{
		padding: 5px;
	}
</style>

  • /store/index.js
//该文件用于创建Vuex中最为核心的store

//引入vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用Vuex
Vue.use(Vuex)
//准备actions--用于响应组件中的动作
const actions = {
	// jia(context,value){
	// 	context.commit('JIA',value);
	// },
	// jian(context,value){
	// 	context.commit('JIAN',value);
	// },
	jiaWait(context,value){
		setTimeout(()=>{
			context.commit('JIA',value);
		},500);
	},
	jiaOdd(context,value){
		if(context.state.sum%2){ //注意这里必须是访问state的sum,如果直接访问sum是undefined
			context.commit('JIA',value);
		}
	},
}
//准备mutations--用于操作数据
const mutations = {
	// mutations中的方法名称一般是大写
	JIA(state,value){
		state.sum += value;
	},
	JIAN(state,value){
		state.sum -= value;
	}
}
//准备state--用于存储数据
const state = {
	sum:0,
	school:'尚硅谷',
	subject:'前端',
}
//准备getters配置项,用于将state中的数据进行加工,类似计算属性,优点是方便进行复用
const getters = {
	bigSum(state){
		return state.sum*10
	}
}

//创建并到处store
export default new Vuex.Store({
	actions:actions,
	mutations:mutations,
	state:state,
	getters:getters
})

3、效果:

image.png

mapState和mapGetters

1、mapState方法:用于帮助我们映射state中的数据为计算属性

computed: {
    //借助mapState生成计算属性,从state中读取数据(对象写法)
    ...mapState({'sum':'sum','school':'school','subject':'subject'}),
			
    //借助mapState生成计算属性,从state中读取数据(数组写法)
    ...mapState(['sum','school','subject']),
}

2、mapGetters方法:用于帮助我们映射getters中的数据为计算属性

computed: {
    //借助mapGetters生成计算属性,bigSum(对象写法)
    ...mapGetters({bigSum:'bigSum'}),
			
    //借助mapGetters生成计算属性,bigSum(数组写法)
    ...mapGetters(['bigSum']),
}

案例

1、需求:在“当前求和放大十倍为:0”下面添加一段话“我在xxx学习xxx”,其中xxx可以更改,并且使用mapState和mapGetters简化名称

2、实现: 在之前案例的基础上只需要对Count.vue进行修改

<template>
	<div>
		<h1>当前求和为:{{sum}}</h1>
		<h1>当前求和放大十倍为:{{bigSum}}</h1>
		<h1>我在{{school}}学习{{subject}}</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>
	import {mapState,mapGetters} from 'vuex'
	export default {
		name:'Count',
		data(){
			return {
				n:1,//用户选择的数字
			}
		},
		computed:{
				
			//借助mapState生成计算属性,从state中读取数据(对象写法)
			//...mapState({'sum':'sum','school':'school','subject':'subject'}),//...对象1 的意思是将对象1中的所有属性展开放入当前对象中
			
			//借助mapGetters生成计算属性,从getters中读取数据(对象写法)
			//...mapGetters({'bigSum':'bigSum'}),
			
			//借助mapState生成计算属性,从state中读取数据(数组写法)
			...mapState(['sum','school','subject']),
			
			//借助mapGetters生成计算属性,从getters中读取数据(数组写法)
			...mapGetters(['bigSum']),
		},
		methods:{
			increment(){
				this.$store.commit('JIA',this.n);
			},
			decrement(){
				this.$store.commit('JIAN',this.n);
			},
			incrementOdd(){				
				this.$store.dispatch('jiaOdd',this.n);
			},
			incrementWait(){
				this.$store.dispatch('jiaWait',this.n);
			},
		},
		mounted() {
			//console.log('Count',this)
		}
	}
</script>

<style lang="css">
	button{
		padding: 5px;
	}
</style>

3、效果:

image.png

mapMutations与mapActions

1、mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数

methods:{
    // 靠mapActions生成:incrementOdd、incrementWait(对象形式)
    ...mapActions({'incrementOdd':'jiaOdd','incrementWait':'jiaWait'}),
    // 靠mapActions生成:incrementOdd、incrementWait(数组形式)
    ...mapActions(['incrementOdd':'jiaOdd','incrementWait':'jiaWait']),
}

2、mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)函数

methods:{
    // 靠mapMutations生成:incrementOdd、incrementWait(对象形式)
    ...mapMutations({'increment':'JIA','decrement':'JIAN'}),
    // 靠mapMutations生成:incrementOdd、incrementWait(数组形式)
    ...mapMutations(['JIA','JIAN']),
}

备注:mapActions与mapMutations使用时,若需要传递参数:在模板中绑定事件时传递好参数否则是事件对象。

案例:

1、需求:使用mapActions与mapMutations简化上一个案例的函数Count.vue

2、实现:

  • Count.vue
<template>
	<div>
		<h1>当前求和为:{{sum}}</h1>
		<h1>当前求和放大十倍为:{{bigSum}}</h1>
		<h1>我在{{school}}学习{{subject}}</h1>
		<select v-model.number="n">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<!-- 这里要加上参数n,才能正确实现功能,不然返回值是鼠标事件会报错 -->
		<button @click="increment(n)">+</button>
		<button @click="decrement(n)">-</button>
		<button @click="incrementOdd(n)">当前求和为奇数再加</button>
		<button @click="incrementWait(n)">等一等再加</button>
	</div>
</template>

<script>
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
	export default {
		name:'Count',
		data(){
			return {
				n:1,//用户选择的数字
			}
		},
		computed:{
			
			//借助mapState生成计算属性,从state中读取数据(对象写法)
			//...mapState({'sum':'sum','school':'school','subject':'subject'}),
			
			//借助mapGetters生成计算属性,从getters中读取数据(对象写法)
			//...mapGetters({'bigSum':'bigSum'}),
			
			//借助mapState生成计算属性,从state中读取数据(数组写法)
			...mapState(['sum','school','subject']),
			
			//借助mapGetters生成计算属性,从getters中读取数据(数组写法)
			...mapGetters(['bigSum']),
		},
		methods:{
			/* increment(){
				this.$store.commit('JIA',this.n);
			},
			decrement(){
				this.$store.commit('JIAN',this.n);
			},
			incrementOdd(){				
				this.$store.dispatch('jiaOdd',this.n);
			},
			incrementWait(){
				this.$store.dispatch('jiaWait',this.n);
			}, */
			
			//借助mapActions生成方法,方法会调用$state.dispathch()函数去联系actions对象(对象写法)
			...mapActions({'incrementOdd':'jiaOdd','incrementWait':'jiaWait'}),
			//借助mapActions生成方法,方法会调用$state.dispathch()函数去联系actions对象(数组写法,但要求Count中名称与index.js中名称相同)
			//...mapActions(['incrementOdd':'jiaOdd','incrementWait':'jiaWait']),
			
			
			//借助mapMutations生成方法,方法会调用$state.commit()函数去联系mutations(对象写法)
			...mapMutations({'increment':'JIA','decrement':'JIAN'}),
			//借助mapMutations生成方法,方法会调用$state.commit()函数去联系mutations(数组写法,但要求Count中名称与index.js中名称相同)
			//...mapMutations(['JIA','JIAN']),
		},
		mounted() {
			//console.log('Count',this)
		}
	}
</script>

<style lang="css">
	button{
		padding: 5px;
	}
</style>

Vuex模块化+命名空间

1、目的:让代码更好维护,让多种数据分类更加明确。

2、修改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,
    }
})

3、开启命名空间后,组件中读取state数据:

//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助mapState读取
...mapState('countAbout',['sum','school','subject'])

4、开启命名空间后,组件中读取getters数据:

//方式一:自己直接读取:
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取:
...mapGetters('countAbout',['bigSum'])

5、开启命名空间后,组件中调用dispatch:

//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

6、开启命名空间后,组件中调用commit:

//方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'})

多组件共享数据案例(实现一个数据不同组件进行显示)

1、需求:在之前的需求上

(1)增加一个Person组件,Person组件中欧给能显示人员列表,并且有添加功能;

(2)在Count组件中增加一段话,统计Person中的人数;

(3)在Persong中添加Count组件的sum;

2、实现:

  • index.js
//该文件用于创建Vuex中最为核心的store

//引入vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用Vuex
Vue.use(Vuex)

//count 组件模块
const countAbout = {
	namespaced:true,
	actions:{
		jiaWait(context,value){
			setTimeout(()=>{
				context.commit('JIA',value);
			},500);
		},
		jiaOdd(context,value){
			if(context.state.sum%2){ //注意这里必须是访问state的sum,如果直接访问sum是undefined
				context.commit('JIA',value);
			}
		},
	},

	mutations:{
		JIA(state,value){
			state.sum += value;
		},
		JIAN(state,value){
			state.sum -= value;
		},
	},

	state:{
		sum:0,
		school:'尚硅谷',
		subject:'前端',
	},

	getters:{
		bigSum(state){
			return state.sum*10
		}
	},
}

//Person组件模块
const personAbout = {
	namespaced:true,
	actions:{},
	mutations:{
		ADD_PERSON(state,value){
			state.personList.unshift(value);
		},
	},

	state:{
		school:'尚硅谷',
		subject:'前端',
		personList:[
			{id:'001',name:'张三'}
		]
	},

	getters:{}
}

//创建并到处store
export default new Vuex.Store({
	modules:{
		countAbout:countAbout,
		personAbout:personAbout
	}
})
  • Person.vue
<template>
    <div>
        <h1>人员列表</h1>
        <h3 style="color:red;">Count组件的求和:{{sum}}</h3>
        <input type="text" placeholder="请输入名字" v-model="name" />
        <button @click="add">添加</button>
        <ul>
            <li v-for="p in personList" :key="p.id">{{p.name}}</li>
        </ul>
    </div>
</template>

<script>
    import {mapState} from 'vuex'
    import {nanoid} from 'nanoid'

    export default {
        name:'Person',
        data(){
            return {
                name:''
            }
        },
        computed:{
            ...mapState('personAbout',['personList']),
            sum(){
                return this.$store.state.countAbout.sum
            },
        },
        methods:{
            add(){
                //创建一个人的类型
                const personObj = {id:nanoid(),name:this.name}
                //添加一个人,这里直接跳过Actions,调用Mutations,因为业务逻辑比较简单
                this.$store.commit('personAbout/ADD_PERSON',personObj)
                //写完清空
                this.name = ''
            }
        }
    }
</script>

  • Count.vue
<template>
	<div>
		<h1>当前求和为:{{sum}}</h1>
		<h1>当前求和放大十倍为:{{bigSum}}</h1>
		<h1>我在{{school}}学习{{subject}}</h1>
		<h3 style="color:red;">Person组件总人数是:{{personList.length}}</h3>
		<select v-model.number="n">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<button @click="increment(n)">+</button>
		<button @click="decrement(n)">-</button>
		<button @click="incrementOdd(n)">当前求和为奇数再加</button>
		<button @click="incrementWait(n)">等一等再加</button>
	</div>
</template>

<script>
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
	export default {
		name:'Count',
		data(){
			return {
				n:1,//用户选择的数字
			}
		},
		computed:{
			...mapState('countAbout',['sum']),
			...mapState('personAbout',['personList','school','subject']),
			...mapGetters('countAbout',['bigSum']),
		},
		methods:{
			...mapActions('countAbout',{'incrementOdd':'jiaOdd','incrementWait':'jiaWait'}),
			...mapMutations('countAbout',{'increment':'JIA','decrement':'JIAN'}),
		},
		mounted() {
			//console.log('Count',this)
		}
	}
</script>

<style lang="css">
	button{
		padding: 5px;
	}
</style>

3、效果:

image.png

新练习

1、需求:在上个案例基础上增加新的如下需求

(1)显示列表中第一个人的名字(从getters读取数据);

(2)加一个按钮只能添加姓王的人(dispatch去联系actions);

(3)可以自动随机生成一个名字,通过axios访问后端服务器(Actions联系后端的API);

(4)将store中person和count写在单独的文件中;

2、实现:

  • /store/index.js
//该文件用于创建Vuex中最为核心的store

//引入vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//引入countAbout
import countAbout from './countAbout'
//引入personAbout
import personAbout from './personAbout'
//使用Vuex
Vue.use(Vuex)



//创建并到处store
export default new Vuex.Store({
	modules:{
		countAbout:countAbout,
		personAbout:personAbout
	}
})
  • /store/countAbout.js
//count 组件模块
export default {
	namespaced:true,
	actions:{
		jiaWait(context,value){
			setTimeout(()=>{
				context.commit('JIA',value);
			},500);
		},
		jiaOdd(context,value){
			if(context.state.sum%2){ //注意这里必须是访问state的sum,如果直接访问sum是undefined
				context.commit('JIA',value);
			}
		},
	},

	mutations:{
		JIA(state,value){
			state.sum += value;
		},
		JIAN(state,value){
			state.sum -= value;
		},
	},

	state:{
		sum:0,
		school:'尚硅谷',
		subject:'前端',
	},

	getters:{
		bigSum(state){
			return state.sum*10
		}
	},
}

  • /store/personAbout.js
import axios from 'axios'
import {nanoid} from 'nanoid'
//Person组件模块
export default {
	namespaced:true,
	actions:{
        addWang(context,value){
            if(value.name.indexOf('王') == 0){
                context.commit('ADD_PERSON',value)
            }
            else{
                alert('添加的人不姓王')
            }
        },
        addRandom(context){
            axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(
                response => {
                    context.commit('ADD_PERSON',{id:nanoid(),name:response.data})
                },
                error => {
                    alert(error.message)
                }
            )
        }
    },
	mutations:{
		ADD_PERSON(state,value){
			state.personList.unshift(value);
		},
	},

	state:{
		school:'尚硅谷',
		subject:'前端',
		personList:[
			{id:'001',name:'张三'}
		]
	},

	getters:{
        showTopName(state){
            return state.personList[0].name
        }
    }
}
  • Person.vue
<template>
    <div>
        <h1>人员列表</h1>
        <h3 style="color:red;">Count组件的求和:{{sum}}</h3>
        <h3>显示列表第一个人:{{showFirstName}}</h3>
        <input type="text" placeholder="请输入名字" v-model="name" />
        <button @click="add">添加</button>
        <button @click="addPersonWang">添加一个姓王的人</button>
        <button @click="addPersonServer">随机添加一个人</button>
        <ul>
            <li v-for="p in personList" :key="p.id">{{p.name}}</li>
        </ul>
    </div>
</template>

<script>
    import {mapGetters, mapState} from 'vuex'
    import {nanoid} from 'nanoid'

    export default {
        name:'Person',
        data(){
            return {
                name:''
            }
        },
        computed:{
            ...mapState('personAbout',['personList']),
            sum(){
                return this.$store.state.countAbout.sum
            },
            showFirstName(){
                return this.$store.getters['personAbout/showTopName']
            }
        },
        methods:{
            add(){
                //创建一个人的类型
                const personObj = {id:nanoid(),name:this.name}
                //添加一个人,这里直接跳过Actions,调用Mutations,因为业务逻辑比较简单
                this.$store.commit('personAbout/ADD_PERSON',personObj)
                //写完清空
                this.name = ''
            },
            addPersonWang(){
                this.$store.dispatch('personAbout/addWang',{id:nanoid(),name:this.name})
                this.name = ''
            },
            addPersonServer(){
                this.$store.dispatch('personAbout/addRandom')
            }
        }
    }
</script>

  • Count.vue
<template>
	<div>
		<h1>当前求和为:{{sum}}</h1>
		<h1>当前求和放大十倍为:{{bigSum}}</h1>
		<h1>我在{{school}}学习{{subject}}</h1>
		<h3 style="color:red;">Person组件总人数是:{{personList.length}}</h3>
		<select v-model.number="n">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<button @click="increment(n)">+</button>
		<button @click="decrement(n)">-</button>
		<button @click="incrementOdd(n)">当前求和为奇数再加</button>
		<button @click="incrementWait(n)">等一等再加</button>
	</div>
</template>

<script>
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
	export default {
		name:'Count',
		data(){
			return {
				n:1,//用户选择的数字
			}
		},
		computed:{
			...mapState('countAbout',['sum']),
			...mapState('personAbout',['personList','school','subject']),
			...mapGetters('countAbout',['bigSum']),
		},
		methods:{
			...mapActions('countAbout',{'incrementOdd':'jiaOdd','incrementWait':'jiaWait'}),
			...mapMutations('countAbout',{'increment':'JIA','decrement':'JIAN'}),
		},
		mounted() {
			//console.log('Count',this)
		}
	}
</script>

<style lang="css">
	button{
		padding: 5px;
	}
</style>

  • App.vue
<template>
    <div>
		<Count></Count>
		<hr />
		<Person></Person>
	</div>
</template>

<script scoped>
	import Count from './components/Count.vue'
	import Person from './components/Person.vue'
	export default {
		name:'App',
		components:{Count,Person},
		mounted() {
			//console.log('App',this);
		}
	}
</script>

<style>
	.container, .meishi{
		display: flex;
		justify-content: space-around;
	}
	video{
		width: 100%;
	}
	img{
		width: 100%;
	}
	h4{
		text-align: center;
	}
	
</style>

3、效果:

image.png