Vuex的使用

1. Vuex

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

Github地址:Vuex

  • 什么时候使用Vuex?
    • 多个组件依赖于同一状态
    • 来自不同组件的行为需要变更同一状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-egpcUWyz-1647751107577)(C:\Users\86188\AppData\Roaming\Typora\typora-user-images\image-20220319213558898.png)]
在这里插入图片描述

2. Vuex工作原理图

在这里插入图片描述

1. state
  • vuex管理的状态对象
  • 它应该是唯一的
2. actions
  • 值为一个对象,包含多个响应用户动作的回调函数
  • 通过commit()来触发mutations中函数的调用,间接更新state
3. 如何触发actions中的回调?

在组件中使用$store.dispatch('对应的action回调名')触发

4. 可以包含异步代码(定时器、Ajax等)

3. Vuex搭建环境

vue2要用vuex3版本,vue3要用vuex4版本

1.安装Vuex包

npm i vue@3

2.在main.js中引入Vuex

import store from './store/index.js'

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

3.在src中创建store文件夹,创建index.js,在index.js配置

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

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,
})
使用Vuex实现求和案例
  • 组件中读取vuex的数据:$store.state.sum
  • 组件中修改vuex中的数据:$store.dispatch('action中的方法名', 数据)$store.commit('mutation中的方法名', 数据)
  • 若没有网络请求或其他业务逻辑,组件也可以越过actions,即不写dispatch,直接写commit

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 {
  // eslint-disable-next-line vue/multi-word-component-names
  name: 'Count',
  data() {
    return {
      n: 1, //用户选择的数字
    }
  },
  methods: {
    increment() {
      this.$store.commit('JIA', this.n)
    },
    decrement() {
      this.$store.commit('JIAN', this.n)
    },
    incrementOdd() {
      if (this.$store.state.sum % 2) {
        this.$store.dispatch('jiaOdd', this.n)
      }
    },
    incrementWait() {
      setTimeout(() => {
        this.$store.dispatch('jiaWait', this.n)
      }, 500)
    },
  },
}
</script>

<style lang="css">
button {
  margin-left: 8px;
}
</style>

store/index.js

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

import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'

// 应用Vuex插件
Vue.use(Vuex)

// 准备actions---用于响应组件中的动作
const actions = {
  // jia(context, value) {
  //   console.log('actions中的jia被调用了')
  //   context.commit('JIA', value)
  // },
  // jian(context, value) {
  //   console.log('actions中的jian被调用了')
  //   context.commit('JIAN', value)
  // },
  jiaOdd(context, value) {
    console.log('actions中的jiaOdd被调用了')
    if (context.state.sum % 2) {
      context.commit('JIA', value)
    }
  },
  jiaWait(context, value) {
    console.log('actions中的jiaWait被调用了')
    setTimeout(() => {
      context.commit('JIA', value)
    }, 500)
  },
}
// 准备mutations---用于操作数据(state)
const mutations = {
  JIA(state, value) {
    console.log('mutations中的JIA被调用了')
    state.sum += value
  },
  JIAN(state, value) {
    console.log('mutations中的JIAN被调用了')
    state.sum -= value
  },
}
// 准备state---用于存储数据
const state = {
  sum: 0, //当前的和
}

// 创建并暴露store
export default new Vuex.Store({
  actions,
  mutations,
  state,
})

在这里插入图片描述

4. getters配置项

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

在store/index.js中配置

const getters = {
    xxx(state){
        return state.数据名
    }
}

//创建并暴露store
export default new Vuex.Store({
  ...
  getters
})
  • 值为一个对象,包含多个用于返回数据的函数
  • 组件中读取数据:$store.getters.xxx

5. 四个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']),
}
3. mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数
methods: {
  //借助mapActions生成,incrementOdd、incrementWait(对象写法)
  ...mapActions({incrementOdd:'jiaOdd',increment:'jiaWait'})

  //借助mapActions生成,incrementOdd、incrementWait(数组写法)
  ...mapActions(['jiaOdd','jiaWait'])
}
4. mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数
methods: {
  //借助mapMutations生成,incrementOdd、incrementWait(对象写法)
  ...mapMutations({increment:'JIA',decrement:'JIAN'})

  //借助mapMutations生成,JIA、JIAN(数组写法)
  ...mapMutations(['JIA','JIAN'])
}

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

5. 求和案例

Count.vue

<template>
  <div>
    <h1>当前求和为:{{ sum }}</h1>
    <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="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="jiaOdd(n)">当前求和为奇数再加</button>
    <button @click="jiaWait(n)">等一等再加</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations } from 'vuex'
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: 'Count',
  data() {
    return {
      n: 1, //用户选择的数字
    }
  },
  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
    }, */

    // 借助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('JIA', this.n)
    },
    decrement() {
      this.$store.commit('JIAN', this.n)
    }, */
    //借助mapMutations生成,incrementOdd、incrementWait(对象写法)
    ...mapMutations({ increment: 'JIA', decrement: 'JIAN' }),

    //借助mapMutations生成,JIA、JIAN(数组写法)
    // ...mapMutations(['JIA', 'JIAN']),

    /* ------------------------------- */
    // 程序员自己写的方法
    /* incrementOdd() {
      if (this.$store.state.sum % 2) {
        this.$store.dispatch('jiaOdd', this.n)
      }
    },
    incrementWait() {
      setTimeout(() => {
        this.$store.dispatch('jiaWait', this.n)
      }, 500)
    }, */
    //借助mapMutations生成,incrementOdd、incrementWait(对象写法)
    // ...mapMutations({ increment: 'JIA', decrement: 'JIAN' }),

    //借助mapMutations生成,JIA、JIAN(数组写法)
    ...mapMutations(['jiaOdd', 'jiaWait']),
  },
}
</script>

<style lang="css">
button {
  margin-left: 8px;
}
</style>

store/index.js

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

import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'

// 应用Vuex插件
Vue.use(Vuex)

// 准备actions---用于响应组件中的动作
const actions = {
  // jia(context, value) {
  //   console.log('actions中的jia被调用了')
  //   context.commit('JIA', value)
  // },
  // jian(context, value) {
  //   console.log('actions中的jian被调用了')
  //   context.commit('JIAN', value)
  // },
  jiaOdd(context, value) {
    console.log('actions中的jiaOdd被调用了')
    if (context.state.sum % 2) {
      context.commit('JIA', value)
    }
  },
  jiaWait(context, value) {
    console.log('actions中的jiaWait被调用了')
    setTimeout(() => {
      context.commit('JIA', value)
    }, 500)
  },
}
// 准备mutations---用于操作数据(state)
const mutations = {
  JIA(state, value) {
    console.log('mutations中的JIA被调用了')
    state.sum += value
  },
  JIAN(state, value) {
    console.log('mutations中的JIAN被调用了')
    state.sum -= value
  },
  jiaOdd(state, value) {
    console.log('mutations中的jiaOdd被调用了')
    if (this.state.sum % 2) {
      state.sum += value
    }
  },
  jiaWait(state, value) {
    console.log('mutations中的jiaWait被调用了')
    setTimeout(() => {
      state.sum += value
    }, 500)
  },
}
// 准备state---用于存储数据
const state = {
  sum: 0, //当前的和
  school: 'b站',
  subject: '前端',
}
// 准备getters---用于将state中的数据进行加工
const getters = {
  bigSum(state) {
    return state.sum * 10
  },
}

// 创建并暴露store
export default new Vuex.Store({
  actions,
  mutations,
  state,
  getters,
})
6. modules
  • 包含多个module
  • 一个module是一个store的配置对象
  • 与一个组件(包含所有共享数据)对应
通过模块化实现多组件共享数据

Count.vue

<template>
  <div>
    <h1>当前求和为:{{ sum }}</h1>
    <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="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="jiaOdd(n)">当前求和为奇数再加</button>
    <button @click="jiaWait(n)">等一等再加</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
export default {
  // eslint-disable-next-line vue/multi-word-component-names
  name: 'Count',
  data() {
    return {
      n: 1, //用户选择的数字
    }
  },
  computed: {
    //借助mapState生成计算属性,从state中读取数据(数组写法)
    ...mapState('countAbout', ['sum', 'school', 'subject']),
    ...mapState('personAbout', ['personList']),

    //借助mapGetters生成计算属性,从getters中读取数据(数组写法)
    ...mapGetters('countAbout', ['bigSum']),
  },
  methods: {
    //借助mapMutations生成,incrementOdd、incrementWait(对象写法)
    ...mapMutations('countAbout', { increment: 'JIA', decrement: 'JIAN' }),

    //借助mapActions生成,incrementOdd、incrementWait(数组写法)
    ...mapActions('countAbout', ['jiaOdd', 'jiaWait']),
  },
}
</script>

<style lang="css">
button {
  margin-left: 8px;
}
</style>

Person.vue

<template>
  <div>
    <h1>人员列表</h1>
    <h3 style="color: red">Count组件求和为:{{ sum }}</h3>
    <h3>列表中第一个人的名字是:{{ firstPersonName }}</h3>
    <input type="text" placeholder="请输入名字" v-model="name" />
    <button @click="add">添加</button>
    <button @click="addWang">添加一个姓王的人</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 {
  // eslint-disable-next-line vue/multi-word-component-names
  name: 'Person',
  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: {
    add() {
      const personObj = { id: nanoid(), name: this.name }
      this.$store.commit('personAbout/ADD_PERSON', personObj)
      this.name = ''
    },
    addWang() {
      const personObj = { id: nanoid(), name: this.name }
      this.$store.dispatch('personAbout/addPersonWang', personObj)
      this.name = ''
    },
    addPersonServer() {
      this.$store.dispatch('personAbout/addPersonServer')
    },
  },
}
</script>

store/index.js

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

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

// 应用Vuex插件
Vue.use(Vuex)

// 创建并暴露store
export default new Vuex.Store({
  modules: {
    countAbout: countOptions,
    personAbout: personOptions,
  },
})

store/count.js

// 求和相关的配置
export default {
  // 开启命名空间
  namespaced: true,
  actions: {
    jiaOdd(context, value) {
      console.log('actions中的jiaOdd被调用了')
      if (context.state.sum % 2) {
        context.commit('JIA', value)
      }
    },
    jiaWait(context, value) {
      console.log('actions中的jiaWait被调用了')
      setTimeout(() => {
        context.commit('JIA', value)
      }, 500)
    },
  },
  mutations: {
    JIA(state, value) {
      console.log('mutations中的JIA被调用了')
      state.sum += value
    },
    JIAN(state, value) {
      console.log('mutations中的JIAN被调用了')
      state.sum -= value
    },
  },
  state: {
    sum: 0, //当前的和
    school: 'b站',
    subject: '前端',
  },
  getters: {
    bigSum(state) {
      return state.sum * 10
    },
  },
}

store/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) {
      // 这个是一个随机生成一句语录的API端口
      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) {
      console.log('mutations中的 ADD_PERSON被调用了')
      state.personList.unshift(value)
    },
  },
  state: {
    personList: [{ id: '001', name: '张三' }],
  },
  getters: {
    firstPersonName(state) {
      return state.personList[0].name
    },
  },
}

在这里插入图片描述

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FG.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值