一、四个 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
- 要在该组件导入 mapState 和 mapGetters
- 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>
如果不使用 mapState 和 mapGetters,则需要在 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; } }
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
要在该组件导入 mapActions 和 mapMutations
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>
二、多组件共享数据
基本功能
- Person 组件添加一个人,Count 组件响应地加一
- Count 组件加一,Person 组件响应地加一
https://www.bilibili.com/video/BV1r3411G7KS?t=15.8
多组件共享
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
- 使用 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
- 使用普通的写法
<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
- 使用模块化编程
- 导入 count.js 和 person.js 文件
- 在 modules 中配置 countOptions 和 personAbout
// 引入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
- 此文件内容为求和相关的配置
- 注意开启命名空间,用于解决不同模块的命名冲突问题。
const countAbout = { namespaced: true, //开启命名空间 actions: {...}, mutations: {...}, state: {...}, getters: { xxx(state){ return state.x } } }
person.js
- 此文件内容为人员信息相关的配置
- 注意开启命名空间,用于解决不同模块的命名冲突问题。
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'})
四、模块化实例
效果如下:
https://www.bilibili.com/video/BV1G3411V73h?t=1.2
vuex模块化
index.js
- 模块化 count.js 和 person.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
- 求和相关的配置
// 求和相关的配置 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
- 人员相关的配置
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>
不积跬步无以至千里 不积小流无以成江海