Vue3实战:从零实现电商购物车功能(含完整代码)

文章目录

    • 一、功能需求分析
    • 二、技术方案选型
    • 三、项目结构设计
    • 四、核心代码实现
      • 1. 创建Pinia Store(购物车状态管理)
      • 2. 商品列表组件
      • 3. 购物车面板组件
    • 五、关键实现细节
      • 1. 数据持久化方案
      • 2. 性能优化方案
      • 3. 异常处理
    • 六、扩展功能实现
      • 1. 服务端同步(示例)
      • 2. 优惠券功能
    • 七、最佳实践建议
    • 八、总结

一、功能需求分析

一个完整的购物车系统需要包含以下核心功能:

  1. 商品展示模块

    • 商品列表展示(图片、名称、价格)
    • 商品规格选择(颜色、尺寸等)
    • 库存状态显示
  2. 购物车操作模块

    • 添加商品到购物车
    • 修改商品数量(±操作)
    • 单选/全选商品
    • 删除单个商品
    • 清空购物车
  3. 计算模块

    • 实时计算选中商品总价
    • 显示商品总数
    • 优惠券计算(可选)
  4. 持久化存储

    • 本地存储购物车数据
    • 登录后同步服务端数据

二、技术方案选型

技术栈 用途说明 版本
Vue3 核心框架 3.4+
Pinia 状态管理 2.1+
Element Plus UI组件库 2.4+
Vue-Router 路由管理 4.2+

三、项目结构设计

src/
├── stores/
│   └── cart.js       # 购物车状态管理
├── components/
│   ├── ProductList.vue  # 商品列表
│   └── CartPanel.vue    # 购物车面板
├── views/
│   ├── HomeView.vue     # 主页面
│   └── DetailView.vue   # 商品详情页
└── utils/
    └── storage.js       # 本地存储工具

四、核心代码实现

1. 创建Pinia Store(购物车状态管理)

// stores/cart.js
import { defineStore } from 'pinia'
import { useStorage } from '@/utils/storage'

export const useCartStore = defineStore('cart', {
  state: () => ({
    items: useStorage('cart_items', []), // 持久化存储
    selected: new Set() // 选中的商品ID
  }),
  actions: {
    // 添加商品
    addItem(product, specs = {}, quantity = 1) {
      const existing = this.items.find(
        item => item.id === product.id && 
        JSON.stringify(item.specs) === JSON.stringify(specs)
      )
      
      if (existing) {
        existing.quantity += quantity
      } else {
        this.items.push({
          ...product,
          specs,
          quantity,
          id: `${product.id}-${Date.now()}` // 生成唯一ID
        })
      }
    },

    // 更新数量
    updateQuantity(id, newQuantity) {
      const item = this.items.find(i => i.id === id)
      if (item) {
        item.quantity = Math.max(1, newQuantity)
      }
    },

    // 删除商品
    removeItem(id) {
      this.items = this.items.filter(i => i.id !== id)
      this.selected.delete(id)
    },

    // 切换选择状态
    toggleSelect(id) {
      if (this.selected.has(id)) {
        this.selected.delete(id)
      } else {
        this.selected.add(id)
      }
    },

    // 全选/取消全选
    toggleAll(checked) {
      if (checked) {
        this.items.forEach(i => this.selected.add(i.id))
      } else {
        this.selected.clear()
      }
    }
  },
  getters: {
    // 计算总金额
    totalAmount: (state) => {
      return state.items.reduce((sum, item) => {
        if (state.selected.has(item.id)) {
          return sum + item.price * item.quantity
        }
        return sum
      }, 0).toFixed(2)
    },
    
    // 选中商品总数
    selectedCount: (state) => state.selected.size
  }
})

2. 商品列表组件





3. 购物车面板组件






五、关键实现细节

1. 数据持久化方案

// utils/storage.js
export const useStorage = (key, defaultValue) => {
  const val = ref(JSON.parse(localStorage.getItem(key)) 
  
  watch(val, (newVal) => {
    localStorage.setItem(key, JSON.stringify(newVal))
  }, { deep: true })

  return val.value || defaultValue
}

2. 性能优化方案

  • 防抖处理:商品数量修改时增加500ms防抖
  • 虚拟滚动:商品列表超过100条时使用虚拟滚动
  • 计算属性缓存:使用computed缓存计算结果

3. 异常处理

// 在store action中添加错误处理
try {
  // 业务逻辑
} catch (error) {
  ElNotification.error({
    title: '操作失败',
    message: error.message
  })
  throw error
}

六、扩展功能实现

1. 服务端同步(示例)

// 在store中添加
async syncCart() {
  const { data } = await axios.post('/api/cart/sync', {
    items: this.items
  })
  this.items = data.cartItems
}

2. 优惠券功能

// 在getters中添加
discountedAmount: (state) => (coupon) => {
  const total = state.totalAmount
  if (coupon.type === 'percent') {
    return total * (1 - coupon.value)
  }
  return total - coupon.value
}

七、最佳实践建议

  1. 组件拆分原则

    • 保持单个组件代码不超过500行
    • 拆分展示型组件和容器组件
    • 使用

你可能感兴趣的:(vue,前端,javascript,vue.js,前端)