Skip to content

Vue状态管理-VueX

995字约3分钟

状态管理Vuex

2024-06-05

Pinia 的前身,主要在 Vue2 中使用

安装

pnpm install vuex

/store/index.js

import Vue from "vue"
import Vuex from "vuex"
import user from "@/store/modules/user"

import { COUNT_MUTATION } from "./mutation-types"

// 仓库
// 安装Vuex插件
Vue.use(Vuex)

const store = new Vuex.Store({
  // 共享数据
  state: {
    count: 0,
  },
  // 修改数据
  mutations: {
    // state 共享数据,payload 传递的参数
    [COUNT_MUTATION]: (state, payload) => {
      state.count = payload
    },
  },
  // methods方法
  actions: {
    // context表示当前store仓库实例
    // 这里可以将context结构为commit,dispatch,state, 如果是子模块,还附有rootState
    // payload为传递过来的数据,可以为具体数值,也可以为对象
    increment: (context /* payload */) => {
      context.commit(COUNT_MUTATION, context.state.count + 1)
      context.commit("user/setUserName", "admin modified")
      context.dispatch("user/totalUserName", "123")
    },
  },
  // 计算属性
  getters: {
    total: (state) => {
      return state.count * 2
    },
  },
  // 子模块
  modules: {
    user,
  },
})

export default store

/store/modules/user.js

子模块

import { COUNT_MUTATION } from "@/store/mutation-types"

export default {
  namespaced: true, // 当设置为true时,除state外,getter、action、mutation访问将额外添加模块名
  state: () => ({
    username: "admin",
  }),
  mutations: {
    setUserName(state, payload) {
      state.username = payload
    },
  },
  actions: {
    // state: 当前模块的state,commit:提交修改函数,rootState:主仓库的state, payload传递的参数
    // eslint-disable-next-line no-unused-vars
    totalUserName(
      { state, commit, rootState, dispatch, getters, rootGetters },
      payload
    ) {
      console.log(payload)
      commit("setUserName", state.username + rootState.count)
      // 调用主仓库中的mutation
      // 第一个参数为type,第二个为传递的参数,第三个指定为根仓库
      commit(COUNT_MUTATION, 10, { root: true })
      // 调用其他模块中的mutation
      // commit('test/mutation', payload, {root: true})
      // 调用主模块的increment方法
      // dispatch('increment', 10, {root: true})
      // 调用其他模块的方法同上
      // 调用当前getters
      // getters.userInfo
      // 调用主仓库的getters
      // rootGetters.total
      // 调用其他模块的getters
      // rootGetters["user/userInfo"]
    },
    // 将待命名空间的actions添加到主仓库中
    testAction: {
      root: true,
      handler(context, payload) {
        console.log(context, payload)
      },
    },
  },
  getters: {
    // state: 当前state, getter当前模块getters,rootState:主仓库state
    userInfo: (state, getters, rootState) => {
      return state.username + getters + rootState.count
    },
  },
}

main.js 中使用 vuex

import Vue from "vue"
import App from "./App.vue"
import store from "@/store"

Vue.config.productionTip = false

new Vue({
  render: (h) => h(App),
  store, // 注入vuex实例
}).$mount("#app")

使用

App.vue

<template>
  <div>
    {{ $store.state.count }}, {{ $store.getters.total }}

    <div>{{ $store.state.user.username }}123</div>
    <!--    <div>{{ $store.getters.userInfo }}</div>-->
    <!--  子模块中的数据使用此方法获取到dom结构中  -->
    <div>{{ $store.getters["user/userInfo"] }}</div>
    <Counter />
    <button @click="increment">+1</button>
    <button @click="reset">Reset</button>
  </div>
</template>

<script>
  import { mapGetters, mapMutations, mapState } from "vuex"
  import Counter from "@/components/Counter.vue"
  import { COUNT_MUTATION } from "@/store/mutation-types"

  // 统一创建子模块的命名空间
  // const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')

  export default {
    name: "App",
    components: {
      Counter,
    },
    methods: {
      /* ===========mapMutations================ */
      // 通过mapMutation方法将仓库中的修改数据方法添加到methods中
      ...mapMutations([COUNT_MUTATION]),
      // 子模块user共享,同上
      ...mapMutations("user", ["setUserName"]),
      // mapActions同上
      increment() {
        // 调用仓库中increment方法
        this.$store.dispatch("increment")
        // 传递参数
        // this.$store.dispatch('increment', 1)
        // 对象方式传递
        /*this.$store.dispatch('increment', {
        count: 1
      })*/
        /*this.$store.dispatch({
        type: 'increment',
        count: 0, // 取值方式:payload.count
      })*/

        this.$store.dispatch("user/totalUserName", 0)

        // user.js中的actions添加到主仓库中的actions中
        this.$store.dispatch("testAction", 0)
      },
      reset() {
        // 对仓库中的数据进行修改操作
        this.$store.commit(COUNT_MUTATION, 0)
        // 传递的参数可以是一个对象
        // this.$store.commit({type: 'setCount', amount: 0})
      },
    },
    computed: {
      /* ==========使用State=============  */
      // 通过mapState将仓库中的数据共享到计算属性当中
      ...mapState(["count"]),
      // 通过对象方式对数据名进行重命名
      ...mapState({ countNum: "count" }),
      // 使用模块中的数据
      ...mapState("user", ["username"]),
      /* ==============使用Getters=================== */
      // 通过mapGetters方法将仓库中的Getters共享到计算属性中
      ...mapGetters(["total"]),
      ...mapGetters({ totalNum: "total" }),
      ...mapGetters("user", ["userInfo"]),
    },
  }
</script>

<style>
  #app {
    font-family: Avenir, Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
  }
</style>

Counter.vue

<script>
  import { mapState } from "vuex"

  export default {
    name: "Counter",
    // 使用对象方式
    computed: mapState({
      // 将仓库中的count共享到当前组件的计算属性当中
      // count: state => state.count,
      // 以上方法的简写形式
      countNum: "count",
      // 使用函数方式更加灵活
      count(state) {
        return state.count + this.localState
      },
    }),
  }
</script>

<template>
  <div>Count: {{ count }} , CountNum: {{ countNum }}</div>
</template>

表单处理

在 vue 组件中

<input :value="message" @input="updateMessage" />
computed: {
  ...mapState({
    message: state => state.obj.message
  })
},
methods: {
  updateMessage (e) {
    this.$store.commit('updateMessage', e.target.value)
  }
}

store 中的 mutation,用于修改数据

mutations: {
  updateMessage (state, message) {
    state.obj.message = message
  }
}