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

Nuxt项目使用Vuex mutation实现迷你购物车商品数量递增功能求助

需修改的核心问题

  1. 原increase mutation未接收商品参数、未定位到购物车中对应商品就直接修改属性,且state.cart是数组,不存在quantity属性
  2. 组件调用increase时仅传了商品id,未传完整商品对象
  3. 原删除/减少逻辑中直接将商品对象作为splice的第一个参数,splice要求第一个参数为数组下标,会导致删除逻辑失效
  4. v-for绑定的key为完整商品对象,不符合Vue规范

代码修改

1. Vue组件调整

<template>
  <div class="bg-white shadow-lg rounded-md absolute right-16">
    <!-- 把key改成商品唯一id -->
    <div
      class="grid grid-cols-2 m-5 mt-9"
      v-for="carts in cart"
      :key="carts.id"
    >
      <img class="w-24 rounded" :src="carts.img" alt="" />
      <div class="grid grid-rows-2">
        <strong class="tracking-wider text-center text-lg font-bold">{{
          carts.title
        }}</strong>

        <div class="grid grid-cols-4 text-center">
          <button
            class="
              text-lg
              font-bold
              text-purple-500
              bg-purple-200
              rounded
              transition-all
              hover:bg-purple-300
            "
            type="button"
            <!-- 传完整商品对象,不是id -->
            v-on:click="increase(carts)"
          >
            +
          </button>
          <p class="text-gray-500 mt-0.5 leading-9 font-normal">
            {{ carts.quantity }}
          </p>
          <button
            class="
              text-lg
              font-bold
              text-purple-500
              bg-purple-200
              rounded
              transition-all
              hover:bg-purple-300
            "
            type="button"
            v-on:click="decrease(carts)"
          >
            -
          </button>
          <button
            class="
              bg-gray-200
              rounded
              p-2
              tracking-wider
              font-bold
              ml-4
              text-gray-500
              transition-all
              hover:bg-gray-300
            "
            v-on:click="removeItem(carts)"
          >
            🗑️
          </button>
        </div>

        <p
          class="
            text-base
            tracking-wider
            mt-2
            text-center text-gray-500
            font-medium
          "
        >
          ${{ carts.price }}
        </p>
      </div>
    </div>

    <div class="flex mx-5 my-8 justify-between">
      <span
        class="
          tracking-wider
          text-lg
          p-4
          font-medium
          justify-center
          align-middle
        "
        >Total: ${{ total }}</span
      >
      <button
        v-on:click="clearCart"
        type="button"
        href=""
        class="
          bg-red-400
          transition-all
          hover:bg-red-500
          p-4
          rounded
          tracking-wider
          text-white text-medium
          font-medium
          leading-none
        "
      >
        Clear Cart
      </button>
    </div>
  </div>
</template>

<script>
import { mapGetters } from "vuex";
export default {
  computed: mapGetters({
    cart: "cart",
    total: "total",
  }),
  methods: {
    removeItem(carts) {
      this.$store.dispatch("removeItem", carts);
    },
    // 统一走action调用,和其他方法逻辑对齐
    increase(carts) {
      this.$store.dispatch("increase", carts);
    },
    decrease(carts) {
      this.$store.dispatch("decrease", carts);
    },
    clearCart() {
      this.$store.dispatch("clearCart");
    },
  },
};
</script>

2. Store调整

export const state = () => ({
    cart: [],
    breeds: [
        // 原有商品列表内容保持不变,此处省略
    ]
});

export const getters = {
    // 重复的checkCart getter可删除,和cart功能完全一致
    cart(state) {
        return state.cart;
    },
    total(state) {
        let total = 0;
        for (let carts of state.cart) {
            // price是字符串,转数字避免计算错误
            total += Number(carts.price) * carts.quantity;
        }
        return total.toFixed(2);
    },
    cartTotal(state) {
        return state.cart.length;
    },
    getPiggyById: (state) => (id) => {
        return state.breeds.find(breed => breed.id == id)
    }
}

export const mutations = {
    pushToCart(state, breed) {
        state.cart.push(breed)
    },
    removeItem(state, carts) {
        // 先找对应商品的下标再删除
        const index = state.cart.findIndex(item => item.id === carts.id)
        if (index > -1) state.cart.splice(index, 1);
    },
    increase(state, carts) {
        // 找到对应商品,数量加1
        const target = state.cart.find(item => item.id === carts.id)
        if (target) target.quantity += 1
    },
    decrease(state, carts) {
        const target = state.cart.find(item => item.id === carts.id)
        if (!target) return
        if (target.quantity > 1) {
            target.quantity -= 1;
        } else {
            const index = state.cart.findIndex(item => item.id === carts.id)
            if (index > -1) state.cart.splice(index, 1);
        }
    },
    clearCart(state) {
        state.cart.splice(0, state.cart.length);
    },
};

export const actions = {
    pushToCart({ commit }, breed) {
        commit("pushToCart", breed)
    },
    removeItem({ commit }, carts) {
        commit("removeItem", carts)
    },
    // 新增increase的action,统一操作入口
    increase({ commit }, carts) {
        commit("increase", carts)
    },
    decrease({ commit }, carts) {
        commit("decrease", carts)
    },
    clearCart({ commit }) {
        commit("clearCart")
    },
}

额外优化建议

  • 商品价格建议存储为数字类型,避免后续计算频繁转类型
  • 加入购物车逻辑建议先判断商品是否已在购物车,存在则直接加数量,不用重复push新对象
  • 可将购物车操作的常用逻辑封装成Vuex的辅助函数,减少重复代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 14:15:05