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

Nuxt 3 商品动态添加购物车及购物车更新问题求助

Nuxt3 购物车更新问题修复方案

问题描述

在Nuxt3项目中,商品详情页点击「加入购物车」按钮后,头部迷你购物车未自动更新,也没有弹出商品已添加的提示。

现有代码分析

商品详情页代码

<template>
    <div class="product-detail py-[40px]">
        <div class="mx-auto container">
            <div class="head-content">
                <a-breadcrumb separator="»">
                  <a-breadcrumb-item>Trang chủ</a-breadcrumb-item>
                  <a-breadcrumb-item><nuxt-link to="/all-product">RAM ECC</nuxt-link></a-breadcrumb-item>
                  <a-breadcrumb-item href="">RAM Samsung DDR4 ECC Registered 64GB 3200AA</a-breadcrumb-item>
                </a-breadcrumb>
            </div>
            <div class="mt-10 flex justify-start items-start ">
                <div class="border-2 w-[381px] relative ">
                    <img :src="ramImg1" alt="" srcset="" class="top-0 overflow-hidden z-10 left-0">
                </div>
                <div class="px-8 flex flex-col">
                    <div class="flex flex-col pb-3 border-b-2 mb-3 w-full">
                        <span class="text-[15px] text-primary font-semibold"><a href="#">RAM ECC</a></span>
                        <span class=" text-2xl">RAM Samsung DDR4 ECC Registered 64GB 3200AA</span>
                    </div>
                    <span>Mã SP: RA021</span>
                    <span class="text-[#c00] text-2xl font-medium my-3">3,900,000 đ</span>
                    <span class=" text-base text-[#777] mb-5">
                        – Tình trạng: mới 100%, date 2022.<br/>
                        – Giá trên không bao gồm VAT.
                    </span>
                    <span class="text-[#f00] text-xl font-medium mb-5">Còn 8 sản phẩm</span>
                    <span class="mb-5 uppercase text-base font-semibold text-[#114eab]">Bảo hành: 3 năm</span>
                    <div class="flex gap-3 items-center mb-5">
                      <button @click="decrement" class="bg-[#E6E6E6] w-[42px] h-[42px] rounded-full">-</button>
                      <div class="text-center pt-2 bg-[#E6E6E6] w-[42px] h-[42px] ">{{ value }}</div>
                      <button @click="increment" class="bg-[#E6E6E6] w-[42px] h-[42px] rounded-full">+</button>
                      <button class="ml-5 btn-wide btn-addcart"><span>Thêm vào giỏ hàng</span></button>
                      <nuxt-link to="/thanh-toan"><button class="btn-wide btn-primary" ><span>Mua ngay</span></button></nuxt-link>
                    </div>
                    <div class="flex gap-5">
                        <span class="text-[#524e6f] font-medium">Chia sẻ trên:</span>
                        <a href="#" class="text-[#524e6f]"><font-awesome-icon icon="fa-brands fa-facebook-f" style="height: 18px;"/></a>
                    </div>
                </div>
            </div>
            <div class="my-5 flex flex-col">
                <span class="text-primary text-lg font-bold">THÔNG TIN SẢN PHẨM</span>
                <span class=" text-base text-[#777] mt-5 leading-10">
                    – RAM Samsung DDR4 ECC Registered 64GB 3200AA.<br/>
                    – RAM được sản xuất bởi hãng Samsung, mới 100% 1 box 25 cây.
                </span>
            </div>
        </div>
    </div>
</template>

迷你购物车代码

<template>
    <div class="mini-cart "> 
        <a-dropdown>
          <a class="ant-dropdown-link" @click.prevent>
            <a-badge count="5">
                <div class="bg-white h-[38px] w-[38px] rounded-full">
                    <font-awesome-icon icon="fa-solid fa-cart-shopping" style="color: #0098d9; padding-top: 30%; padding-left: 30%;" />
                </div>
            </a-badge>
          </a>
          <template #overlay>
                <div class="w-[300px] bg-white shadow-lg p-5 flex flex-col ml-[5%] mt-[6%]">
                    <div class="flex justify-start gap-2">
                        <div class="h-[60px] w-[60px]">
                            <img :src="ramImg1" alt="" srcset="">
                        </div>
                        <div class="flex flex-col text-center mb-3 w-[155px]">
                            <span class=" text-primary font-bold">RAM Samsung DDR4 ECC Registered 32GB 3200AA</span>
                            <span class="text-[#414042] text-base">1 x <span class="text-[#c00] text-base font-bold">2,200,000 đ</span></span>
                        </div>
                        <div>
                            <button href="#" class="close"></button>
                        </div>
                    </div>
                    <center><button class="uppercase bg-[#0d6efd1a] py-1 px-[19px] text-primary font-medium rounded-[5px] h-[35px] w-[200px]"><span>xoá tất cả sản phẩm</span></button></center>
                    <div class="flex justify-between text-base text-[#777] font-bold my-3 border-t-[1px] pt-3">
                        <span>Tổng số phụ:</span>
                        <span>2,200,000 đ</span>
                    </div>
                    <nuxt-link to="/gio-hang"><button class="w-full mt-[17px] h-10 border-primary border-[1px] text-primary py-1 rounded-full"><span>Xem giỏ hàng</span></button></nuxt-link>
                    <nuxt-link to="/thanh-toan" class="text-white font-medium"><button class="w-full mt-[10px] h-10 bg-primary rounded-full py-1 text-white"><span>Thanh toán</span></button></nuxt-link>
                </div>
          </template>
        </a-dropdown>
    </div>
</template>

问题根源

  1. 「加入购物车」按钮未绑定点击事件,点击后无任何逻辑执行
  2. 迷你购物车数据为硬编码(如count="5"、商品信息固定),未与实际购物车数据联动
  3. 无全局状态管理机制共享购物车数据,组件间无法同步更新

修复方案

步骤1:创建Pinia购物车状态管理

Nuxt3官方推荐使用Pinia做状态管理,先安装依赖:

npm install pinia @pinia/nuxt

在nuxt.config.ts中注册Pinia:

export default defineNuxtConfig({
  modules: ['@pinia/nuxt']
})

创建stores/cart.ts:

import { defineStore } from 'pinia'

export interface CartItem {
  id: string
  name: string
  price: number
  quantity: number
  image: string
}

export const useCartStore = defineStore('cart', {
  state: () => ({
    items: [] as CartItem[]
  }),
  getters: {
    totalCount: (state) => state.items.reduce((sum, item) => sum + item.quantity, 0),
    totalPrice: (state) => state.items.reduce((sum, item) => sum + item.price * item.quantity, 0)
  },
  actions: {
    addItem(item: CartItem) {
      const existingItem = this.items.find(i => i.id === item.id)
      if (existingItem) {
        existingItem.quantity += item.quantity
      } else {
        this.items.push(item)
      }
    },
    removeItem(id: string) {
      this.items = this.items.filter(i => i.id !== id)
    },
    clearCart() {
      this.items = []
    }
  }
})

步骤2:修改商品详情页,实现添加购物车逻辑

更新商品详情页的模板和脚本部分:

<template>
    <!-- 原有模板内容不变,仅修改「加入购物车」按钮 -->
    <button @click="addToCart" class="ml-5 btn-wide btn-addcart"><span>Thêm vào giỏ hàng</span></button>
</template>

<script setup>
import { useCartStore } from '~/stores/cart'

const cartStore = useCartStore()

// 商品基础数据(可从接口获取,这里模拟)
const product = {
  id: 'RA021',
  name: 'RAM Samsung DDR4 ECC Registered 64GB 3200AA',
  price: 3900000,
  image: ramImg1 // 对应原有模板中的图片变量
}

// 数量控制变量
const value = ref(1)

const increment = () => {
  value.value++
}

const decrement = () => {
  if (value.value > 1) {
    value.value--
  }
}

const addToCart = () => {
  cartStore.addItem({
    ...product,
    quantity: value.value
  })
  // 弹出添加成功提示(原生实现)
  alert('商品已添加到购物车!')
}
</script>

步骤3:修改迷你购物车,动态渲染数据

更新迷你购物车组件:

<template>
    <div class="mini-cart "> 
        <a-dropdown>
          <a class="ant-dropdown-link" @click.prevent>
            <a-badge :count="cartStore.totalCount">
                <div class="bg-white h-[38px] w-[38px] rounded-full">
                    <font-awesome-icon icon="fa-solid fa-cart-shopping" style="color: #0098d9; padding-top: 30%; padding-left: 30%;" />
                </div>
            </a-badge>
          </a>
          <template #overlay>
                <div class="w-[300px] bg-white shadow-lg p-5 flex flex-col ml-[5%] mt-[6%]">
                    <!-- 动态渲染购物车商品列表 -->
                    <div v-if="cartStore.items.length === 0" class="text-center py-5">
                        <span>Giỏ hàng trống</span>
                    </div>
                    <div v-else v-for="item in cartStore.items" :key="item.id" class="flex justify-start gap-2 mb-3">
                        <div class="h-[60px] w-[60px]">
                            <img :src="item.image" alt="" srcset="">
                        </div>
                        <div class="flex flex-col text-center mb-3 w-[155px]">
                            <span class=" text-primary font-bold">{{ item.name }}</span>
                            <span class="text-[#414042] text-base">{{ item.quantity }} x <span class="text-[#c00] text-base font-bold">{{ formatPrice(item.price) }} đ</span></span>
                        </div>
                        <div>
                            <button @click="cartStore.removeItem(item.id)" class="close"></button>
                        </div>
                    </div>
                    
                    <center v-if="cartStore.items.length > 0">
                        <button @click="cartStore.clearCart" class="uppercase bg-[#0d6efd1a] py-1 px-[19px] text-primary font-medium rounded-[5px] h-[35px] w-[200px]"><span>xoá tất cả sản phẩm</span></button>
                    </center>
                    
                    <div v-if="cartStore.items.length > 0" class="flex justify-between text-base text-[#777] font-bold my-3 border-t-[1px] pt-3">
                        <span>Tổng số phụ:</span>
                        <span>{{ formatPrice(cartStore.totalPrice) }} đ</span>
                    </div>
                    
                    <nuxt-link to="/gio-hang" v-if="cartStore.items.length > 0">
                        <button class="w-full mt-[17px] h-10 border-primary border-[1px] text-primary py-1 rounded-full"><span>Xem giỏ hàng</span></button>
                    </nuxt-link>
                    <nuxt-link to="/thanh-toan" class="text-white font-medium" v-if="cartStore.items.length > 0">
                        <button class="w-full mt-[10px] h-10 bg-primary rounded-full py-1 text-white"><span>Thanh toán</span></button>
                    </nuxt-link>
                </div>
          </template>
        </a-dropdown>
    </div>
</template>

<script setup>
import { useCartStore } from '~/stores/cart'

const cartStore = useCartStore()

// 格式化价格为千分位
const formatPrice = (price: number) => {
  return price.toLocaleString('vi-VN')
}
</script>

效果验证

  1. 点击商品详情页的「加入购物车」按钮,会弹出提示,同时头部购物车图标上的数字更新
  2. 点击头部购物车图标,下拉菜单中会显示实际添加的商品、数量和总价
  3. 支持修改商品数量后添加,以及删除商品、清空购物车等操作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 23:25:01