Vue —— 进阶 Vuex(一)(四个 map 的用法、模块化和命名空间)

Vue2.x 系列文章目录

内容 参考链接
Vue2.x - 基础 Vue2.x - 基础
Vue2.x - 进阶 Vue2.x - 进阶脚手架
Vue2.x - 高级 Vuex Vuex概念、工作原理、环境搭建、基本使用、getters
Vue2.x - 高级 Vuex Vuex 四个 map 的用法、模块化和命名空间
Vue2.x - 高级 Vue-router 路由的概念、基本使用
Vue2.x - 高级 Vue-router 嵌套路由、query参数、命名路由、params参数、props配置
Vue2.x - 高级 Vue-router replace属性、编程式路由导航、缓存路由组件、路由的专属钩子
Vue2.x - 高级 Vue-router 全局路由守卫
Vue3.0 - 新增 Vue3.0 新增内容
Vue2.x 项目(附源码) Vue + ElementUI 后台管理项目(附源码)
Vue3.0 项目 Vue3.0 企业级 App

文章目录

        • 一、四个 map 的用法
          • 1. mapState 方法
          • 2. mapGetters 方法
          • 实例:使用 mapState 和 mapGetters
          • 3. mapActions 方法
          • 4. mapMutations 方法
          • 实例:使用 mapActions 和 mapMutations
        • 二、多组件共享数据
        • 三、模块化(module)和命名空间(namespace)
          • 1. 目的
          • 2. 修改 .store/xxx.js 文件
          • 3. 组件中读取 state 数据
          • 4. 组件中读取 getters 数据
          • 5. 组件中调用 dispatch
          • 6. 组件中调用 commit
        • 四、模块化实例


一、四个 map 的用法

1. mapState 方法

用于帮助我们映射 state 中的数据为计算属性

	computed: {
	  // 借助 mapState 生成计算属性:sum、school、subject (对象写法)
	  ...mapState({ sum: "sum", school: "school", subject: "subject" })
	  // 借助 mapState 生成计算属性:sum、school、subject (数组写法)
	  ...mapState(['sum', 'school', 'subject'])
	}
2. mapGetters 方法

用于帮助我们映射 getters 中的数据为计算属性

	computed:{
	  // 借助 mapGetters 生成计算属性:bigSum (对象写法)
	  ...mapGetters({bigSum: bigSum})
	  // 借助 mapGetters 生成计算属性:bigSum (数组写法)
	  ...mapGetters(['bigSum'])
	}
实例:使用 mapState 和 mapGetters

使用 mapState 和 mapGetters,可以少些很多代码。

index.js

	// 该文件用于创建Vuex中最为核心的store
	// 引入vue核心库
	import Vue from 'vue'
	// 引入Vuex
	import Vuex from 'vuex'
	// 应用Vuex插件
	Vue.use(Vuex)
	
	// 准备actions——用于响应组件中的动作
	const actions = {
	    addOdd(context, value){
	        console.log('actions中的addOdd被调用了');
	        if(context.state.sum % 2){
	            context.commit('ADD',value)
	        }
	    },
	    addWait(context, value){
	        console.log('actions中的addWait被调用了');
	        setTimeout(()=>{
	            context.commit('ADD', value)
	        },500)
	    }
	}
	// 准备mutations——用于修改state中的数据(state)
	const mutations = {
	    ADD(state, value){
	        console.log('mutations中的ADD被调用了',state, value);
	        state.sum += value
	    },
	    SUB(state, value){
	        console.log('mutations中的SUB被调用了',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({
	    actions,
	    mutations,
	    state,
	    getters
	})

Count.vue

  1. 要在该组件导入 mapStatemapGetters
  2. import { mapState, mapGetters } from "vuex";
	<template>
	  <div>
	    <h2>当前求和为:{{ sum }}</h2>
	    <h3>当前求和放大10倍:{{ bigSum }}</h3>
	    <h3>我在{{ school }},学习{{ subject }}</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="sub(n)">-</button>
	    <button @click="addOdd(n)">当前求和为奇数再加</button>
	    <button @click="addWait(n)">等一等再加</button>
	  </div>
	</template>
	
	<script>
	import { mapState, mapGetters } from "vuex";
	export default {
	  name: "myCount",
	  data() {
	    return {
	      n: 1, //用户选择的数字
	    };
	  },
	  computed: {
	    // 借助mapState生成计算属性,从state中读取数据 (对象写法)
	    //...mapState({ sum: "sum", school: "school", subject: "subject" }),
	    // 借助mapState生成计算属性,从state中读取数据 (数组写法)
	    ...mapState(['sum','school','subject']),
	
	    // 借助mapGetters生成计算属性,从getters中读取数据(对象写法)
	    //...mapGetters({bigSum: 'bigSum'}),
	    // 借助mapGetters生成计算属性,从getters中读取数据(数组写法)
	    ...mapGetters(['bigSum'])
	
	  },
	  methods: {
	    increment() {
	      this.$store.commit("ADD", this.n);
	    },
	    decrement() {
	      this.$store.cmommit("SUB", this.n);
	    },
	    incrementOdd() {
	      this.$store.dispatch("addOdd", this.n);
	    },
	    incrementWait() {
	      this.$store.dispatch("addWait", this.n);
	    },
	  },
	};
	</script>
	
	<style scoped>
	button {
	  margin-left: 5px;
	}
	</style>

Vue —— 进阶 Vuex(一)(四个 map 的用法、模块化和命名空间)_第1张图片

如果不使用 mapStatemapGetters,则需要在 computed 中手动配置如下代码。

	computed: {
	  sum() {
	    return this.$store.state.sum;
	  },
	  school() {
	    return this.$store.state.school;
	  },
	  subject() {
	    return this.$store.state.subject;
	  },
	  bigSum() {
	    return this.$store.getters.bigSum;
	  }
	}

Vue —— 进阶 Vuex(一)(四个 map 的用法、模块化和命名空间)_第2张图片

3. mapActions 方法

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

	methods: {
	  // 靠mapActions生成:addOdd、addWait (对象写法)
	  ...mapActions({addOdd: 'addOdd', addWait: 'addWait'})
	  // 靠mapActions生成:addOdd、addWait (数组写法)
	  ...mapActions(['addOdd', 'addWait'])
	}
4. mapMutations 方法

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

	methods: {
      // 靠mapMutations生成:ADD、SUB (对象写法)
      ...mapMutations({add: 'ADD', sub: 'SUB'})
      // 靠mapMutations生成:ADD、SUB (数组写法)
      ...mapMutations(['ADD', 'SUB'])
	}
实例:使用 mapActions 和 mapMutations

index.js 不变

Count.vue

  1. 要在该组件导入 mapActionsmapMutations
  2. import { mapActions, mapMutations} from "vuex";
	<template>
	  <div>
	    <h2>当前求和为:{{ sum }}</h2>
	    <h3>当前求和放大10倍:{{ bigSum }}</h3>
	    <h3>我在{{ school }},学习{{ subject }}</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="sub(n)">-</button>
	    <button @click="addOdd(n)">当前求和为奇数再加</button>
	    <button @click="addWait(n)">等一等再加</button>
	  </div>
	</template>
	
	<script>
	import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
	export default {
	  name: "myCount",
	  data() {
	    return {
	      n: 1, //用户选择的数字
	    };
	  },
	  computed: {
	    // 借助mapState生成计算属性,从state中读取数据 (对象写法)
	    // ...mapState({ sum: "sum", school: "school", subject: "subject" }),
	    // 借助mapState生成计算属性,从state中读取数据 (数组写法)
	    ...mapState(["sum", "school", "subject"]),
	
	    // 借助mapGetters生成计算属性,从getters中读取数据(对象写法)
	    //...mapGetters({bigSum: 'bigSum'}),
	    // 借助mapGetters生成计算属性,从getters中读取数据(数组写法)
	    ...mapGetters(["bigSum"]),
	  },
	  methods: {
	    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations (对象的写法)
	    ...mapMutations({add: 'ADD', sub: 'SUB'}),
	    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations (数组的写法)
	    //...mapMutations(['ADD','SUB']), //此时上面的绑定也要 @ADD @SUB
	    //借助mapActions生成对应的方法,方法中会调用dispatch去联系actions (对象写法)
	    ...mapActions({addOdd: 'addOdd', addWait: 'addWait'})
	    //借助mapActions生成对应的方法,方法中会调用dispatch去联系actions (数组写法)
	    //...mapActions(['addOdd','addWait'])
	  },
	};
	</script>
	
	<style scoped>
	button {
	  margin-left: 5px;
	}
	</style>

二、多组件共享数据

基本功能

  1. Person 组件添加一个人,Count 组件响应地加一
  2. Count 组件加一,Person 组件响应地加一

多组件共享

index.js

	// 该文件用于创建Vuex中最为核心的store
	// 引入vue核心库
	import Vue from 'vue'
	// 引入Vuex
	import Vuex from 'vuex'
	// 应用Vuex插件
	Vue.use(Vuex)
	
	// 准备actions——用于响应组件中的动作
	const actions = {
	    addOdd(context, value) {
	        console.log('actions中的addOdd被调用了');
	        if (context.state.sum % 2) {
	            context.commit('ADD', value)
	        }
	    },
	    addWait(context, value) {
	        console.log('actions中的addWait被调用了');
	        setTimeout(() => {
	            context.commit('ADD', value)
	        }, 500)
	    }
	}
	// 准备mutations——用于修改state中的数据(state)
	const mutations = {
	    ADD(state, value) {
	        console.log('mutations中的ADD被调用了');
	        state.sum += value
	    },
	    SUB(state, value) {
	        console.log('mutations中的SUB被调用了');
	        state.sum -= value
	    },
	    ADD_PERSON(state, value) {
	        console.log('mutations中的ADD_PERSON被调用了');
	        state.personList.unshift(value)
	    }
	}
	// 准备state——用于存储具体的数据
	const state = {
	    sum: 0, //当前的和
	    school: '清华大学',
	    subject: 'Web前端',
	    personList: [{
	        id: '001',
	        name: '张三'
	    }]
	}
	const getters = {
	    bigSum() {
	        return state.sum * 10
	    }
	}
	// 创建并暴露store
	export default new Vuex.Store({
	    actions,
	    mutations,
	    state,
	    getters
	})

Count.vue

  1. 使用 map 写法
	<template>
	  <div>
	    <h2>当前求和为:{{ sum }}</h2>
	    <h3>当前求和放大10倍:{{ bigSum }}</h3>
	    <h3>我在{{ school }},学习{{ subject }}</h3>
	    <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="add(n)">+</button>
	    <button @click="sub(n)">-</button>
	    <button @click="addOdd(n)">当前求和为奇数再加</button>
	    <button @click="addWait(n)">等一等再加</button>
	  </div>
	</template>
	
	<script>
	import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
	export default {
	  name: "myCount",
	  data() {
	    return {
	      n: 1, //用户选择的数字
	    };
	  },
	  computed: {
	    // 借助mapState生成计算属性,从state中读取数据 (对象写法)
	    // ...mapState({ sum: "sum", school: "school", subject: "subject" }),
	    // 借助mapState生成计算属性,从state中读取数据 (数组写法)
	    ...mapState(["sum", "school", "subject", "personList"]),
	
	    // 借助mapGetters生成计算属性,从getters中读取数据(对象写法)
	    //...mapGetters({bigSum: 'bigSum'}),
	    // 借助mapGetters生成计算属性,从getters中读取数据(数组写法)
	    ...mapGetters(["bigSum"]),
	  },
	  methods: {
	    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations (对象的写法)
	    ...mapMutations({ add: "ADD", sub: "SUB" }),
	    //借助mapMutations生成对应的方法,方法中会调用commit去联系mutations (数组的写法)
	    // ...mapMutations(['ADD','SUB']), //此时上面的绑定也要 @ADD @SUB
	
	    ...mapActions({ addOdd: "addOdd", addWait: "addWait" }),
	    // ...mapActions(['addOdd','addWait'])
	  },
	};
	</script>
	
	<style scoped>
	button {
	  margin-left: 5px;
	}
	</style>

Person.vue

  1. 使用普通的写法
	<template>
	  <div>
	    <h3>人员列表</h3>
	    <h3 style="color: red">Count组件的求和为:{{ sum }}</h3>
	    <input type="text" placeholder="请输入名字" v-model="name" />
	    <button @click="addPerson">添加</button>
	    <ul>
	      <li v-for="p in personList" :key="p.id">{{ p.name }}</li>
	    </ul>
	  </div>
	</template>
	
	<script>
	import { nanoid } from "nanoid";
	export default {
	  name: "myPerson",
	  data() {
	    return {
	      name: "",
	    };
	  },
	  computed: {
	    personList() {
	      return this.$store.state.personList;
	    },
	    sum() {
	      return this.$store.state.sum;
	    },
	  },
	  methods: {
	    addPerson() {
	      const personObj = { id: nanoid(), name: this.name };
	      this.$store.commit("ADD_PERSON", personObj);
	      this.name = "";
	    },
	  },
	};
	</script>

三、模块化(module)和命名空间(namespace)

1. 目的

让代码更好维护,让多种数据分类更加明确。

2. 修改 .store/xxx.js 文件

index.js

  1. 使用模块化编程
  2. 导入 count.jsperson.js 文件
  3. 在 modules 中配置 countOptionspersonAbout
	// 引入vue核心库
	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
	    }
	})

count.js

  1. 此文件内容为求和相关的配置
  2. 注意开启命名空间,用于解决不同模块的命名冲突问题。
	const countAbout = {
	    namespaced: true, //开启命名空间
	    actions: {...},
	    mutations: {...},
	    state: {...},
	    getters: {
	        xxx(state){
	            return state.x
	        }
	    }
	}

person.js

  1. 此文件内容为人员信息相关的配置
  2. 注意开启命名空间,用于解决不同模块的命名冲突问题。
	const personAbout = {
	    namespaced: true, //开启命名空间
	    actions: {},
	    mutations: {},
	    state: {},
	    getters: {}
	}
3. 组件中读取 state 数据

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

	//方式一:自己读取数据
	this.$store.state.personAbout.personlist
	//方式二:借助 mapState 读取
	...mapState('countAbout', ['sum', 'school', 'subject'])
4. 组件中读取 getters 数据

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

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

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

	//方式一:自己直接调用 dispatch
	this.$store.dispatch('personAbout/addPersonWang', person)
	//方式二:借助 mapActions 调用
	...mapActions('countAbout', {addOdd: 'addOdd', addWait: 'addWait'})
6. 组件中调用 commit

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

	//方式一:自己直接调用 commit
	this.$store.commit('personAbout/ADD_PERSON', person)
	//方式二:借助 mapMutations 调用
	...mapMutations('countAbout', {add: 'ADD', sub: 'SUB'})

四、模块化实例

效果如下:

vuex模块化

index.js

  1. 模块化 count.jsperson.js
	// 引入vue核心库
	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
	    }
	})

count.js

  1. 求和相关的配置
	// 求和相关的配置
	export default {
	  // 开启命名空间
	  namespaced: true,
	  // 用于响应组件中的动作
	  actions: {
	    addOdd(context, value) {
	      console.log('actions中的addOdd被调用了');
	      if (context.state.sum % 2) {
	        context.commit('ADD', value)
	      }
	    },
	    addWait(context, value) {
	      console.log('actions中的addWait被调用了');
	        setTimeout(() => {
	          context.commit('ADD', value)
	        }, 500)
	     }
	  },
	  // 用于修改state中的数据(state)
	  mutations: {
	    ADD(state, value) {
	      console.log('mutations中的ADD被调用了');
	      state.sum += value
	    },
	    SUB(state, value) {
	      console.log('mutations中的SUB被调用了');
	      state.sum -= value
	    },
	  },
	  // 用于存储具体的数据
	  state: {
	    sum: 0, //当前的和
	    school: '清华大学',
	    subject: 'Web前端',
	  },
	  getters: {
	    bigSum(state) {
	      return state.sum * 10
	    }
      }
	}

person.js

  1. 人员相关的配置
	import axios from 'axios'
	import { nanoid } from 'nanoid'
	export default {
	  // 开启命名空间
	  namespaced: true,
	  // 用于响应组件中的动作
	  actions: {
	    addPersonWang(context, value){
	      if(value.name.indexOf('王') === 0){
	        context.commit('ADD_PERSON', value)
	      }else{
	        alert('添加的人必须姓王!')
	        }
	      },
	    //连接服务器
	    addPersonServer(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)
	        }
	      )
	    }
      },
	  // 用于修改state中的数据(state)
	  mutations: {
	    ADD_PERSON(state, value) {
	      console.log('mutations中的ADD_PERSON被调用了');
	      state.personList.unshift(value)
	    }
	  },
	  // 用于存储具体的数据
	  state: {
	    personList: [{
	      id: '001',
	      name: '张三'
	    }]
	  },
	  getters: {
	    firstPersonName(state){
	      return state.personList[0].name
	    }
	  }
    }

Count.vue

	<template>
	  <div>
	    <h2>当前求和为:{{ sum }}</h2>
	    <h3>当前求和放大10倍:{{ bigSum }}</h3>
	    <h3>我在{{ school }},学习{{ subject }}</h3>
	    <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="add(n)">+</button>
	    <button @click="sub(n)">-</button>
	    <button @click="addOdd(n)">当前求和为奇数再加</button>
	    <button @click="addWait(n)">等一等再加</button>
	  </div>
	</template>
	 
	<script>
	import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
	export default {
	  name: "myCount",
	  data() {
	    return {
	      n: 1, //用户选择的数字
	    };
	  },
	  computed: {
	    ...mapState("countAbout", ['sum','school','subject']),
	    ...mapState("personAbout", ['personList']),
	    ...mapGetters('countAbout', ['bigSum']),
	  },
	  methods: {
	    ...mapMutations('countAbout', { add: "ADD", sub: "SUB" }),
	    ...mapActions('countAbout', { addOdd: "addOdd", addWait: "addWait" }),
	  },
	};
	</script>
	
	<style scoped>
	button {
	  margin-left: 5px;
	}
	</style>

Person.vue

	<template>
	  <div>
	    <h3>人员列表</h3>
	    <h3 style="color: red">Count组件的求和为:{{ sum }}</h3>
	    <h3>列表中第一个人的名字是:{{firstPersonName}}</h3>
	    <input type="text" placeholder="请输入名字" v-model="name" />
	    <button @click="addPerson">添加</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 { nanoid } from "nanoid";
	export default {
	  name: "myPerson",
	  data() {
	    return {
	      name: "",
	    };
	  }, 
	  computed: {
	    personList() {
	      return this.$store.state.personAbout.personList;
	    },
	    sum() {
	      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 = "";
	    },
	    addPersonWang(){
	        const personObj = { id: nanoid(), name: this.name };
	        this.$store.dispatch('personAbout/addPersonWang', personObj)
	        this.name = ''
	    },
	    addPersonServer(){
	      this.$store.dispatch('personAbout/addPersonServer')
	    }
	  },
	};
	</script>
	
	<style scoped>
	button{
	  margin-left: 5px;
	}
	</style>

不积跬步无以至千里 不积小流无以成江海

你可能感兴趣的:(Vue2,vue.js,javascript,前端)