You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用Vuex Store多模块实现收支余额计算与列表展示

方案选型建议

两种实现方式没有绝对的优劣,按照你的业务场景选就行:

  • 如果总余额、合并收支列表的逻辑只在当前这一个组件里用,直接在组件内引入两个模块的getter计算就行,不需要额外修改store代码,更轻量
  • 如果后续有多个组件都需要用到总余额、合并收支数据,就把计算逻辑放到根store的getter里统一维护,避免多组件重复写计算逻辑

具体实现方式

方式1:组件内直接引入两个模块的getter完成计算

这是你当前场景最快捷的实现方式,只需要修改你的余额组件代码即可:

<template>
  <div>
    <!-- 总余额 -->
    <div class="total-value" :style="balanceColor">
      Balance: {{ totalBalance }}
    </div>
    <!-- 合并的收支列表 -->
    <div class="record-list">
      <div v-for="record in mergedRecordList" :key="record.id">
        <span>{{ record.type }}</span>
        <span>{{ record.value }}</span>
        <span>{{ record.comment }}</span>
      </div>
    </div>
  </div>
</template>

<script>
import {mapGetters} from 'vuex';

export default {
  name: 'TBalance',
  computed: {
    balanceColor: function() {
      return {
        color: this.totalBalance === 0 ? 'black' : this.totalBalance > 0 ? 'green' : 'red'
      }
    },
    // 计算总余额
    totalBalance() {
      const incomeTotal = Object.values(this.incomeList).reduce((acc, item) =>  acc + item.value, 0)
      const outcomeTotal = Object.values(this.outcomeList).reduce((acc, item) =>  acc + item.value, 0)
      return incomeTotal + outcomeTotal
    },
    // 合并收支列表,如果需要按时间排序可以在这里加sort逻辑
    mergedRecordList() {
      return [...Object.values(this.incomeList), ...Object.values(this.outcomeList)]
    },
    // 同时引入两个命名空间模块的getter
    ...mapGetters("income", ["incomeList"]),
    ...mapGetters("outcome", ["outcomeList"]),
  },
}
</script>

方式2:根store统一封装计算逻辑

如果多组件复用这些数据,就修改根store的index.js,新增全局getter:

import Vue from "vue";
import Vuex from "vuex";
import income from "./modules/income";
import outcome from "./modules/outcome";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  getters: {
    // 总余额
    totalBalance: (state, getters) => {
      const incomeTotal = Object.values(getters['income/incomeList']).reduce((acc, item) => acc + item.value, 0)
      const outcomeTotal = Object.values(getters['outcome/outcomeList']).reduce((acc, item) => acc + item.value, 0)
      return incomeTotal + outcomeTotal
    },
    // 合并后的收支列表
    mergedRecordList: (state, getters) => {
      return [...Object.values(getters['income/incomeList']), ...Object.values(getters['outcome/outcomeList'])]
    }
  },
  modules: {
    income,
    outcome,
  },
});

之后组件直接从根getter取数据即可:

<script>
import {mapGetters} from 'vuex';

export default {
  name: 'TBalance',
  computed: {
    balanceColor: function() {
      return {
        color: this.totalBalance === 0 ? 'black' : this.totalBalance > 0 ? 'green' : 'red'
      }
    },
    ...mapGetters(["totalBalance", "mergedRecordList"]),
  },
}
</script>

多Vuex模块在组件内使用的核心逻辑

因为你给两个模块都加了namespaced: true的命名空间配置,所以不管是mapGetters、mapState还是mapActions、mapMutations,只要第一个参数传入对应模块的命名空间名称,就可以引入对应模块的方法/状态,一个组件可以同时引入任意多个模块的资源。

内容的提问来源于stack exchange,提问作者1 2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 18:09:02