vueX: vue插件,处理组件之间共享数据的读 && 写

  • 引入demo(就一个Count组件,加法计算)

    ### Count.vue(基础的写死版)
    <template>
    	<div>
    		<h1>当前求和为 ???</h1>
    		<select>
    			<option value="1">1</option>
    			<option value="2">2</option>
    			<option value="3">3</option>
    		</select>
    		<button type="button">+</button>
    		<button type="button">-</button>
    		<button type="button">求和为奇数再加</button>
    		<button type="button">等一等再加</button>
    	</div>
    	
    </template>
    
    <script>
    	export default {
    		name:'Count',
    	}
    </script>
    
    <style>
    	button {
    		margin-left: 5px;
    	}
    </style>
    
    
  • 现在使用纯vue来实现

    <template>
    	<div>
    		<h1>当前求和为{{sum}}</h1>
    		<!--v-model用来收集用户输入的值,并转换为Number,否则会出现字符串数字拼接,计算结果异常-->
    		<select v-model.number="n"> <!--number修饰符-->
    			<option value="1">1</option>
    			<option value="2">2</option>
    			<option value="3">3</option>
    		</select>
    		<button type="button" @click="increment">+</button>
    		<button type="button" @click="decrement">-</button>
    		<button type="button" @click="incrementOdd">求和为奇数再加</button>
    		<button type="button" @click="incrementWait">等一等再加</button>
    	</div>
    	
    </template>
    
    <script>
    	export default {
    		name:'Count',
    		data(){
    			return {
    				sum:0,
    				n:1
    			}
    		},
    		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
    				},1000)
    			},
    		}
    		
    	}
    </script>
    
    <style>
    	button {
    		margin-left: 5px;
    	}
    </style>
    
    
  • vueX原理图解

  • 注意事项

    - Actions 有时候可以pass,即不是必须项(需要和后端交互的时候就必须)
    

Vuex 环境搭建

- npm i vuex@3 # vue2搭配vuex3的版本,若安装最新版,则出现版本问题,会报错

- Vue.use(vuex)

- store 存放的位置

- vc ==> store
  • store 存放的位置处理(新建store目录,创建index.js)

    # index.js
    import Vue from "vue"
    import Vuex from "vuex"
    
    Vue.use(Vuex) // 把使用插件的逻辑写在这,而不是写在main.js(会报错,和vue脚手架编译顺序有关系)
    
    const actions = {} // 响应组件的动作(服务员)
    
    const mutations = {} // 操作 state的数据(厨师)
    
    const state = {} // 存储数据(菜)
    
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state,
    })
    
    # main.js
    import Vue from 'vue'
    import App from './App.vue'
    
    // import store from './store/index.js'
    import store from './store' // 这种引入方式也可以,store这个名字可以随便取
    
    new Vue({
      render: h => h(App),
      store, // 创建vm的时候,传入store配置项
      beforeCreate(){
    	  Vue.prototype.$bus = this
      }
    }).$mount('#app')
    
    - 现在,在App组件打印vc实例对象,多了一个'vc.$store'属性,包含很多强大的API
      比如,dispatch/commit/state
    
    
  • 注意vue脚手架的编译顺序

    - 先执行所有的import语句,在执行其他(以下语句,会先执行两个import语句,最后才执行console.log)
    
    	import test1 from './test1'
    	console.log(100)
    	console.log(200)
    	import test2 from './test2'
    	
    - 所以,在main.js使用引入插件的通常写法,来引入vuex的时候,会报错(报错提示必须先使用Vue.use(vuex))
    	
    	### main.js
    	import store from './store' // 这句会先被执行,所以报错
        Vue.use(Vuex)
    
  • 搭建vuex环境小结

    - 概念: 是vue插件,处理多组件之间的'共享数据',适用于任意组件之间的通讯
    
    - 搭建步骤见上面
    
  • 把Count案例修改成'vuex'版(这里以一个单组件为例)

    ### index.js
    import Vue from "vue"
    import Vuex from "vuex"
    
    Vue.use(Vuex)
    
    const actions = {}
    
    const mutations = {}
    
    const state = {
    	sum:0 // 准备共享的数据
    }
    
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state,
    })
    
    ### Count.vue
    <template>
    	<div>
    		<!--这里修改成state存放的共享数据-->
    		<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 type="button" @click="increment">+</button>
    		<button type="button" @click="decrement">-</button>
    		<button type="button" @click="incrementOdd">求和为奇数再加</button>
    		<button type="button" @click="incrementWait">等一等再加</button>
    	</div>
    	
    </template>
    
    <script>
    	export default {
    		name:'Count',
    		data(){
    			return {
    				// sum:0, // 不再存放组件自身
    				n:1
    			}
    		},
    		methods:{
    			// 以下逻辑要重新写
    			increment(){
    			},
    			decrement(){
    				
    			},
    			incrementOdd(){
    				
    			},
    			incrementWait(){
    				
    			},
    		}
    		
    	}
    </script>
    
    <style>
    	button {
    		margin-left: 5px;
    	}
    </style>
    
    
    ### Count.vue
    <template>
    	<div>
    		<h1>当前求和为{{$store.state.sum}}</h1>
    		......
    	</div>
    	
    </template>
    
    <script>
    	export default {
    		name:'Count',
    		data(){
    			return {
    				n:1
    			}
    		},
    		methods:{
    			increment(){
    				// this.sum += this.n
    				this.$store.dispatch('jia',this.n) // 调用dispatch分发"动作",并传参
    			},
    			decrement(){
    				
    			},
    			incrementOdd(){
    				
    			},
    			incrementWait(){
    				
    			},
    		}
    		
    	}
    </script>
    
    ### index.js
    import Vue from "vue"
    import Vuex from "vuex"
    
    Vue.use(Vuex)
    
    const actions = {
    	jia(context,value){ // 响应jia动作,context是miniStore对象,value就是传过来的值
    		context.commit('JIA',value) // 提交动作(一般提交过去的动作,习惯大写命名)
    	}
    }
    
    const mutations = {
    	JIA(state,value){ // 接收动作并处理数据
    		state.sum += value
    	}
    }
    
    const state = {
    	sum:0
    }
    
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state,
    })
    
  • 加法的运算搞定,其他算法一样的逻辑处理

    ### Count.vue
    <template>
    	<div>
    		<h1>当前求和为{{$store.state.sum}}</h1>
    		......
    	</div>
    	
    </template>
    
    <script>
    	export default {
    		name:'Count',
    		data(){
    			return {
    				n:1
    			}
    		},
    		methods:{
    			increment(){
    				......
    			},
    			decrement(){
    				// his.sum -= this.n
    				this.$store.dispatch('jian',this.n)
    			},
    			incrementOdd(){
    				// if(this.sum % 2){
    				// 	this.sum += this.n
    				// }
    				this.$store.dispatch('odd',this.n)
    			},
    			incrementWait(){
    				// setTimeout(()=>{
    				// 	this.sum += this.n
    				// },1000)
    				this.$store.dispatch('wait',this.n)
    			},
    		}
    		
    	}
    </script>
    
    ### index.js
    import Vue from "vue"
    import Vuex from "vuex"
    
    Vue.use(Vuex)
    
    const actions = {
    	jia(context,value){
    		context.commit('JIA',value)
    	},
    	// 响应动作并提交
    	jian(context,value){
    		context.commit('JIAN',value)
    	},
    	odd(context,value){
    		context.commit('ODD',value)
    	},
    	wait(context,value){
    		context.commit('WAIT',value)
    	}
    }
    
    const mutations = {
    	// 接收动作并处理具体的逻辑
    	JIA(state,value){
    		state.sum += value
    	},
    	JIAN(state,value){
    		state.sum -= value
    	},
    	ODD(state,value){
    		if(state.sum % 2) {
    			state.sum += value
    		}
    	},
    	WAIT(state,value){
    		setTimeout(()=>{
    			state.sum += value
    		},1000)
    	},
    	
    	
    }
    
    const state = {
    	sum:0
    }
    
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state,
    })
    
  • 可以发现,actions这步其实可以跳过,因为只是提交而已(根据vuex原理图,没有涉及到后端的交互)

    一模一样的效果

    ### index.js
    import Vue from "vue"
    import Vuex from "vuex"
    
    Vue.use(Vuex)
    
    const actions = {
    
    	// 注释掉
    	// jia(context,value){
    	// 	context.commit('JIA',value)
    	// },
    	// jian(context,value){
    	// 	context.commit('JIAN',value)
    	// },
    	odd(context,value){
    		context.commit('ODD',value)
    	},
    	wait(context,value){
    		context.commit('WAIT',value)
    	}
    }
    
    const mutations = {
    	JIA(state,value){
    		state.sum += value
    	},
    	JIAN(state,value){
    		state.sum -= value
    	},
    	......
    	
    ### Count.vue
    ......
    methods:{
    			increment(){
    				// this.sum += this.n
    				// this.$store.dispatch('jia',this.n)
    				// 这里直接提交了,不再进行分发
    				this.$store.commit('JIA',this.n)
    			},
    			decrement(){
    				// his.sum -= this.n
    				// this.$store.dispatch('jian',this.n)
    				this.$store.commit('JIAN',this.n)
    			},
    
  • 目前为止小结

- 组件提交事件,并提交要处理的数据
-vuex 接收事件(数据),和'共享数据'进行交互
  • context小拓展: 当业务逻辑相对复杂的时候,如果全部都在一个函数可能不妥

    可以利用context.dispatch()作分发,原本一个函数搞定的事情,拆分成3个搞定

### index.js
......
const actions = {
	......
	odd(context,value){
		// context.commit('ODD',value) // 不再提交,而是进行逻辑分发
		console.log('做了一些事情')
		context.dispatch('demo1',value) // 分发到demo1,继续处理剩余的逻辑
	},
	demo1(context,value){
		console.log('demo1做的事情')
		context.dispatch('demo2',value) // 分发到demo2,继续处理剩余的逻辑
	},
	demo2(context,value){
		console.log('demo2做的事情')
		context.commit('ODD',value) // 事情终于做好了,提交到mutations
	},
	......
}
  • context 是 miniStore,所以'$store'也可以作相同的事情

    - 先: $store.dispatch('action中的方法名',数据)
    - 然后: $store.commit('mutation中的方法名',数据)
    

钩子getters 介绍(可以理解为'计算属性共享版',而state就是vm的data)

  • 概念: 当 state 中的数据需要经过加工后再使用,可以使用 getters 加工

  • 引入场景: 把求和放大十倍,可以这么搞(组件里面使用计算属性来实现)

    ### Count.vue
    ......
    <div>
    		<h1>当前求和为{{$store.state.sum}}</h1>
    		<!-- <h1>当前和放大十倍: {{$store.state.sum*10}}</h1> -->
    		<h1>当前和放大十倍: {{tenSum}}</h1> <!--使用计算属性实现-->
    ......
    computed:{
    			tenSum(){
    				return this.$store.state.sum * 10
    			}
    		}
    
    
  • 上述示例有个缺陷,计算属性只能在本组件使用,局限性高,别的组件想使用,不能复用

    现在,使用 getters解决这个问题

    ### index.js
    import Vue from "vue"
    import Vuex from "vuex"
    
    Vue.use(Vuex)
    
    const actions = {
    	......
    }
    
    const mutations = {
    	......
    }
    
    const state = {
    	sum:0
    }
    
    const getters = { //定义getters
    	tenSum(state){ // 接收state加工数据并返回
    		return state.sum * 10
    	}
    }
    
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state,
    	getters // 添加配置项
    })
    
    ### Count.vue
    ......
    <div>
    		<h1>当前求和为{{$store.state.sum}}</h1>
    		<!-- <h1>当前和放大十倍: {{$store.state.sum*10}}</h1> -->
    		<!-- <h1>当前和放大十倍: {{tenSum}}</h1> -->
    		<h1>当前和放大十倍: {{$store.getters.tenSum}}</h1>
    

映射mapState && mapGetters(简写代码)

  • 引入场景: 增加两个字段,并把插值搞成属性的形式,精简插值代码(vue推荐)
### index.js
......
const state = {
	sum:0,
	name:'JimGreen', // 新增
	age:20
}
......

### Count.vue
<template>
	<div>
		<!-- <h1>当前求和为{{$store.state.sum}}</h1> -->
		<h1>当前求和为{{sum}}</h1>
		<!-- <h1>当前和放大十倍: {{$store.state.sum*10}}</h1> -->
		<!-- <h1>当前和放大十倍: {{tenSum}}</h1> -->
		<h1>当前和放大十倍: {{tenSum}}</h1>
		<!-- <h1>我是: {{$store.state.name}},我的年龄是: {{$store.state.age}}</h1> -->
		<h1>我是: {{name}},我的年龄是: {{age}}</h1>
		......
	</div>
	
</template>

<script>
	export default {
		name:'Count',
		data(){
			return {
				n:1
			}
		},
		methods:{
			......
		},
		computed:{
			
			sum(){ // 精简插值语法
				return this.$store.state.sum
			},
			tenSum(){
				return this.$store.getters.tenSum
			},
			name(){
				return this.$store.state.name
			},
			age(){
				return this.$store.state.age
			}
		}
		
	}
</script>

<style>
	button {
		margin-left: 5px;
	}
</style>

  • 计算属性代码中,可以使用 映射 进一步精简

    ### index.js
    ......
    const state = {
    	sum:0,
    	name:'JimGreen',
    	age:20
    }
    
    ### Count.vue
    ......
    <script>
    	import {mapState} from 'vuex' // 导入映射函数
    	
    	export default {
    		name:'Count',
    		data(){
    			return {
    				n:1
    			}
    		},
    		methods:{
    			......
    		},
    		computed:{
    			// 全都注释掉
    			// tenSum(){
    			// 	return this.$store.state.sum * 10
    			// }
    			
    			// sum(){
    			// 	return this.$store.state.sum
    			// },
    			// name(){
    			// 	return this.$store.state.name
    			// },
    			// age(){
    			// 	return this.$store.state.age
    			// },
    			
    			// 解构赋值,注意最后要加逗号,因为下面还有一个 tenSum
    			...mapState({sum:'sum',name:'name',age:'age'}), 
    			// 数组写法也可以,一模一样
    			// ...mapState(['sum','name','age']),
    			tenSum(){
    				return this.$store.getters.tenSum
    			}
    		},
    		mounted(){
    			// 这里不能简写成{sum,name,age},因为组件没有sum,name,age变量
    			const dataObj = mapState({sum:'sum',name:'name',age:'age'}) 
    			console.log(dataObj) // 包含映射关系的数据对象(比如{sum:func...})
    		},
    	}
    </script>
    
  • mapGetters 是同样的套路

    <script>
    	import {mapState,mapGetters} from 'vuex' // 导入
    	
    	export default {
    		name:'Count',
    		data(){
    			return {
    				n:1
    			}
    		},
    		methods:{
    			......
    		},
    		computed:{
    			...mapState({sum:'sum',name:'name',age:'age'}),
    			...mapGetters(['tenSum']), // 一样的套路写法(这里使用数组写法)
    			// tenSum(){
    			// 	return this.$store.getters.tenSum
    			// }
    		},
    		mounted(){
    			......
    		},
    	}
    </script>
    
  • 小结

    - mapState()方法用于帮助我们映射state中的数据为计算属性
    
    - mapGetters()方法用于帮助我们映射getters中的数据为计算属性
    
    - 有两种写法
    
    	- 对象写法
    	- 数组写法
    
    - 目的都是为了精简代码
    

    mapMutations 和 mapActions

  • methods里面,映射mutations里面的方法(也是精简代码)

### Count.vue(对象写法)
<template>
	<div>
		......
		<!-- <button type="button" @click="increment">+</button> -->
		<!--传给mutations的参数,是n,写在这里,-->
		<button type="button" @click="increment(n)">+</button>
		<!-- <button type="button" @click="decrement">-</button> -->
		<button type="button" @click="decrement(n)">-</button>
		......
	</div>
	
</template>

<script>
	import {mapState,mapGetters,mapMutations} from 'vuex' // 导入mapMutations
	
	export default {
		name:'Count',
		data(){
			return {
				n:1
			}
		},
		methods:{
			// increment(){
			// 	// this.sum += this.n
			// 	// this.$store.dispatch('jia',this.n)
			// 	this.$store.commit('JIA',this.n)
			// },
			// decrement(){
			// 	// his.sum -= this.n
			// 	// this.$store.dispatch('jian',this.n)
			// 	this.$store.commit('JIAN',this.n)
			// },
			
			// increment对应mutations的'JIA',其他类同
			...mapMutations({increment:'JIA',decrement:'JIAN'}),
			......
		},
		
### index.js
......
const mutations = {
	JIA(state,value){ // 要映射的方法源
		state.sum += value
	},
	JIAN(state,value){
		state.sum -= value
	},
	......
}
  • 数组写法(还要修改html元素里面的方法名称,个人觉得,对象写法比较好...)
### Count.vue
<template>
	<div>
		......
		<!-- <button type="button" @click="increment">+</button> -->
		<!-- <button type="button" @click="increment(n)">+</button> -->
		<!--修改函数名称为JIA-->
		<button type="button" @click="JIA(n)">+</button>
		<!-- <button type="button" @click="decrement">-</button> -->
		<button type="button" @click="JIAN(n)">-</button>
		<!-- <button type="button" @click="decrement(n)">-</button> -->
		......
	</div>
	
</template>
......
methods:{
			......
			// ...mapMutations({increment:'JIA',decrement:'JIAN'}),
			// 映射的名称,以 mutations里面的为准...
			...mapMutations(['JIA','JIAN']),
  • 这里如果不想修改html元素的方法名称,可以这么搞(但是不推荐这么写,即使用另外一个函数去代理,该函数体里面调用映射方法并传参)
### Count.vue
<template>
	<div>
		......
		<!--采用之前的写法-->
		<button type="button" @click="increment">+</button>
		<!-- <button type="button" @click="increment(n)">+</button> -->
		<!-- <button type="button" @click="JIA(n)">+</button> -->
		<button type="button" @click="decrement">-</button>
		<!-- <button type="button" @click="JIAN(n)">-</button> -->
		<!-- <button type="button" @click="decrement(n)">-</button> -->
		......
	</div>
</template>
......
methods:{
			increment(){ // 代理函数
				this.add(this.n) // 函数体调用映射方法并传参
			},
			decrement(){
				this.subtract(this.n)
			},
			// 写法不变
			...mapMutations({add:'JIA',subtract:'JIAN'}),
  • mapActions是一样的套路(对象写法)
### Count.vue
<template>
	<div>
		......
		<!--对象写法,增加传参-->
		<button type="button" @click="incrementOdd(n)">求和为奇数再加</button>
		<button type="button" @click="incrementWait(n)">等一等再加</button>
	</div>
	
</template>

<script>
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
	
	export default {
		name:'Count',
		data(){
			return {
				n:1
			}
		},
		methods:{
			
			// ...mapMutations({increment:'JIA',decrement:'JIAN'}),
			
			// incrementOdd(){
			// 	// if(this.sum % 2){
			// 	// 	this.sum += this.n
			// 	// }
			// 	this.$store.dispatch('odd',this.n)
			// },
			// incrementWait(){
			// 	// setTimeout(()=>{
			// 	// 	this.sum += this.n
			// 	// },1000)
			// 	this.$store.dispatch('wait',this.n)
			// },
			// 映射actions里面的方法
			...mapActions({incrementOdd:'odd',incrementWait:'wait'}),
		},
		......
	}
</script>


  • 数组写法
<template>
	<div>
		......
		<!-- <button type="button" @click="incrementOdd(n)">求和为奇数再加</button> -->
		<!--名称得变-->
		<button type="button" @click="odd(n)">求和为奇数再加</button>
		<!-- <button type="button" @click="incrementWait(n)">等一等再加</button> -->
		<button type="button" @click="wait(n)">等一等再加</button>
	</div>
</template>

<script>
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
	
	export default {
		name:'Count',
		data(){
			return {
				n:1
			}
		},
		methods:{
			
			...mapMutations({increment:'JIA',decrement:'JIAN'}),
			// 数组写法
			...mapActions(['odd','wait']),
		},
		......
	}
</script>

  • 小结
- mapActions方法: 帮助我们生成与actions对话的方法,即包含: $store.disptch(xxx)的函数

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

- 均支持对象 && 数组 写法

- 注意事项: 两个方法若需要传参,则需要在模板中绑定事件时传递好参数,否则参数默认是'事件对象'

vuex模块化

  • 引入场景: 两个组件互相引用vuex的共享数据

    新增person组件,列表展示个人信息数据

### Person.vue
<template>
	<div>
		<h1>人员列表</h1>
		<input type="text" placeholder="请输入名字" />
		<button type="button">添加</button>
		<ul>
			<!--渲染数据-->
			<li v-for="person in personList" :key="person.id">{{person.name}}</li>
		</ul>
	</div>
</template>

<script>
	import {mapState} from 'vuex'
	
	export default {
		name:'Person',
		computed:{
			// ...mapState(['personList']), // 这里先不这样写
			personList(){ // 使用普通的计算属性实现
				return this.$store.state.personList
			}
		}
	}
</script>

### index.js
......
const state = {
	sum:0,
	name:'JimGreen',
	age:20,
	
	personList:[ // 新增Person组件数据源
		{id:1,name:'JimGreen'},
		{id:2,name:'KateGreen'},
		{id:3,name:'LiLei'},
		{id:4,name:'HanMeiMei'}
	]
}

  • Person组件实现按钮添加人员信息的功能
### index.js(mutations加工Person组件传过来的数据)
......
const mutations = {
	......
	ADD_PERSON(state,value){
		state.personList.unshift(value) // 往数组最开头插入
	}
	
	
}

const state = {
	sum:0,
	name:'JimGreen',
	age:20,
	
	personList:[
		{id:1,name:'JimGreen'},
		{id:2,name:'KateGreen'},
		{id:3,name:'LiLei'},
		{id:4,name:'HanMeiMei'}
	]
}

### Person.vue
<template>
	<div>
		<!--v-model收集用户输入-->
		<input type="text" placeholder="请输入名字" v-model="nameMsg" />
		<!--新增add点击事件-->
		<button type="button" @click="add">添加</button>
		......
	</div>
</template>

<script>
	import {mapState} from 'vuex'
	// import nanoid from 'nanoid' // 这样写会报错,要包裹{}
	import {nanoid} from 'nanoid'
	
	export default {
		name:'Person',
		data(){
			return {
				nameMsg:'' // 默认值
			}
		},
		computed:{
			......
		},
		methods:{
			add(){
				// 根据用户输入的值,构造数据并传给mutations加工
				const personObj = {id:nanoid(),name:this.nameMsg}
				this.$store.commit('ADD_PERSON',personObj)
				this.nameMsg = ''
			}
		}
	}
</script>

<style>
</style>

  • Count组件引用PersonList数据,可以这么干
### Count.vue
<template>
	<div>
		......
		<h1 style="color: red;">Person组件的总人数为{{personList.length}}</h1>
......
computed:{
			// 多映射一个personList字段
			...mapState({sum:'sum',name:'name',age:'age',personList:'personList'}),
			......
		},
  • 模块化vuex的思想
 - store(原来的结构)
 
 	- actions
 	- mutations
 	- state
 	- getters
 	
 - 如果组件很多的时候,上述四个子模块的逻辑就很乱了,后期维护相当困难
   解决办法:为每一个组件都划分上述四个子模块,逻辑就清晰很多
   
 - store(现在的结构)
 	
     - a组件
        - actions
        - mutations
        - state
        - getters
    - b组件
        - actions
        - mutations
        - state
        - getters
### index.js
import Vue from "vue"
import Vuex from "vuex"

Vue.use(Vuex)

const countOptions = { // 存放Count组件逻辑相关
	namespaced:true, // 取个名字(必须)
	actions:{
		jia(context,value){
			context.commit('JIA',value)
		},
		jian(context,value){
			context.commit('JIAN',value)
		},
		odd(context,value){
			context.commit('ODD',value)
			// context.dispatch('demo1',value)
		},
		// demo1(context,value){
		// 	console.log('demo1做的事情')
		// 	context.dispatch('demo2',value)
		// },
		// demo2(context,value){
		// 	console.log('demo2做的事情')
		// 	context.commit('ODD',value)
		// },
		
		wait(context,value){
			context.commit('WAIT',value)
		}
	},
	mutations:{
		JIA(state,value){
			state.sum += value
		},
		JIAN(state,value){
			state.sum -= value
		},
		ODD(state,value){
			if(state.sum % 2) {
				state.sum += value
			}
		},
		WAIT(state,value){
			setTimeout(()=>{
				state.sum += value
			},1000)
		},
	},
	state:{
		sum:0,
		name:'JimGreen',
		age:20,
	},
	getters:{
		tenSum(state){
			return state.sum * 10
		}
	}
}

const personOptions = { // 存放Person组件逻辑相关
	namespaced:true,
	mutations:{
		ADD_PERSON(state,value){
			state.personList.unshift(value)
		}
	},
	state:{
		personList:[
			{id:1,name:'JimGreen'},
			{id:2,name:'KateGreen'},
			{id:3,name:'LiLei'},
			{id:4,name:'HanMeiMei'}
		]
	}
}


export default new Vuex.Store({
	// actions,
	// mutations,
	// state,
	// getters
	modules:{ // 模块化
		countAbout:countOptions,// 模块名称
		personAbout:personOptions
	}
	
})

### Count.vue
<template>
	<div>
		
		<h1>当前求和为{{sum}}</h1>
		
		<h1>当前和放大十倍: {{tenSum}}</h1>
		
		<h1>我是: {{name}},我的年龄是: {{age}}</h1>
		<h1 style="color: red;">Person组件的总人数为{{personList.length}}</h1>
		<select v-model.number="n">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
							<!--需要传参-->
		<button type="button" @click="increment(n)">+</button>
		<button type="button" @click="decrement(n)">-</button>
		<button type="button" @click="odd(n)">求和为奇数再加</button>
		<button type="button" @click="wait(n)">等一等再加</button>
	</div>
	
</template>

<script>
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
	
	export default {
		name:'Count',
		data(){
			return {
				n:1
			}
		},
		methods:{
			// 传入模块名+配置对象
			...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN',odd:'ODD',wait:'WAIT'}),
			......
		},
		computed:{
			// 传入模块名+配置对象
			...mapState('countAbout',['name','age','sum']),
			...mapState('personAbout',['personList']),
			...mapGetters('countAbout',['tenSum'])
			......
		},
		......
	}
</script>
  • Person组件使用模块化演示(不使用map映射,手动写不那么方便,稍繁琐)
    • 拆分index.js,变成 index.js,count.js,person.js
### count.js
export default {
		namespaced:true,
		actions:{
			jia(context,value){
				context.commit('JIA',value)
			},
			jian(context,value){
				context.commit('JIAN',value)
			},
			odd(context,value){
				context.commit('ODD',value)
				// context.dispatch('demo1',value)
			},
			
			wait(context,value){
				context.commit('WAIT',value)
			}
		},
		mutations:{
			JIA(state,value){
				state.sum += value
			},
			JIAN(state,value){
				state.sum -= value
			},
			ODD(state,value){
				if(state.sum % 2) {
					state.sum += value
				}
			},
			WAIT(state,value){
				setTimeout(()=>{
					state.sum += value
				},1000)
			},
		},
		state:{
			sum:0,
			name:'JimGreen',
			age:20,
		},
		getters:{
			tenSum(state){
				return state.sum * 10
			}
		}
	}
	
### person.js
export default {
	namespaced:true,
	actions:{
		// 新增王姓人员专属api
		addPersonWang(context,value){
			if(value.name.indexOf('王') == 0){
				context.commit('ADD_PERSON',value)
			}else{
				alert('王姓专属噢!')
			}
		}
	},
	mutations:{
		ADD_PERSON(state,value){
			state.personList.unshift(value)
		}
	},
	state:{
		personList:[
			{id:1,name:'JimGreen'},
			{id:2,name:'KateGreen'},
			{id:3,name:'LiLei'},
			{id:4,name:'HanMeiMei'}
		]
	},
	getters:{ // 新增 输出最开头人员的名字
		firstPersonName(state){
			return state.personList[0].name
		}
	}
}

### index.js
import Vue from "vue"
import Vuex from "vuex"
import countOptions from './count.js' // 引入
import personOptions from './person.js'

Vue.use(Vuex)

export default new Vuex.Store({
	modules:{
		countAbout:countOptions, // 配置
		personAbout:personOptions
	}
	
})

  • Person组件的逻辑如下
### Person.vue
<template>
	<div>
		<h1>人员列表</h1>
		<input type="text" placeholder="请输入名字" v-model="nameMsg" />
		<button type="button" @click="add">添加</button>
		<ul>
			<li v-for="person in personList" :key="person.id">{{person.name}}</li>
		</ul>
		<!--新增以下三个逻辑-->
		<h1>当前求和为: {{sum}}</h1>
		<h1>第一个人的姓名为: {{firstPersonName}}</h1>
		<button type="button" @click="addWang">添加王姓人员</button>
	</div>
</template>

<script>
	import {mapState} from 'vuex'
	import {nanoid} from 'nanoid'
	
	export default {
		name:'Person',
		data(){
			return {
				nameMsg:''
			}
		},
		computed:{
			personList(){
				return this.$store.state.personAbout.personList // 通过 personAbout.personList 正常展示数据
			},
			sum(){ 
				return this.$store.state.countAbout.sum // 通过countAbout.sum 正常展示数据
			},
			firstPersonName(){
				// return this.$store.getters.personAbout.firstPersonName // 语法不是这样写的
				return this.$store.getters['personAbout/firstPersonName'] // 可以这样获取属性['属性值']
			}
		},
		methods:{
			add(){
				const personObj = {id:nanoid(),name:this.nameMsg}
				this.$store.commit('personAbout/ADD_PERSON',personObj)
				this.nameMsg = ''
			},
			addWang(){ // 分发actions
				const personObj = {id:nanoid(),name:this.nameMsg}
				// 注意这种语法: dispatch('personAbout/addPersonWang',personObj)
				this.$store.dispatch('personAbout/addPersonWang',personObj)
				this.nameMsg = ''
			}
		}
	}
</script>

<style>
</style>

  • actions和后端交互演示
- 后端API地址: https://api.uixsj.cn/hitokoto/get?type=social
	- 返回一句话
	
### person.js
import axios from 'axios'
import {nanoid} from 'nanoid' // 不能写成: import nanoid from 'nanoid',会报错

export default {
	namespaced:true,
	actions:{
		addPersonWang(context,value){
			......
		},
		addPersonServer(context){
			// 向后端发请求并打包数据,发送给mutations
			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:{
		personList:[
			......
		]
	},
	getters:{
		......
	}
}

### Person.vue
<template>
	<div>
		......
		// 新增
		<button type="button" @click="addPersonServer">后端交互</button>
		
	</div>
</template>

<script>
	import {mapState} from 'vuex'
	import {nanoid} from 'nanoid'
	
	export default {
		name:'Person',
		data(){
			......
		},
		computed:{
			......
		},
		methods:{
			......
			addPersonServer(){ // 分发请求
				this.$store.dispatch('personAbout/addPersonServer')
			}
		}
	}
</script>

<style>
</style>

7.模块化+命名空间(小结)

  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'}),
    
  7. 手写语法方面,只有state语法和想象的一样,其他均不一样