前言

在现代前端开发中,购物车功能是电商平台的核心模块之一。本文将详细介绍如何使用 Vue 3、Pinia 状态管理和 Element Plus UI 组件库构建一个完整的企业级购物车系统。

技术栈概览

  • ​Vue 3​​ - 渐进式 JavaScript 框架

  • ​Pinia​​ - Vue 官方推荐的状态管理库

  • ​Element Plus​​ - 基于 Vue 3 的组件库

  • ​Vue Router​​ - 官方路由管理器

一、Pinia 状态管理实现

1.1 Store 结构设计

import { defineStore } from "pinia";
import { ref, computed } from 'vue'

export const useCartStore = defineStore('cart', () => {
  // 状态定义
  const cartList = ref([])
  const userStore = useUserStore()
  const isLogin = computed(() => userStore.userInfo.token)
  
  // 操作方法
  const addCart = async (goods) => {
    if(isLogin.value) {
      // 已登录逻辑
      await insertCartAPI(goods.skuId, goods.count)
      const res = await fineNewCartListAPI()
      cartList.value = res.result
    } else {
      // 未登录逻辑
      const item = cartList.value.find((item) => goods.skuId === item.skuId)
      item ? item.count++ : cartList.value.push(goods)
    }
  }
  
  // 计算属性
  const allCount = computed(() => 
    cartList.value.reduce((a, b) => a + b.count, 0)
  )
  
  return { cartList, addCart, allCount }
}, {
  persist: true // 状态持久化
})

1.2 核心功能解析

​状态持久化​​:通过 persist: true配置,购物车数据自动保存到 localStorage,页面刷新不丢失。

​登录状态适配​​:智能判断用户登录状态,分别处理本地购物车和服务器购物车同步。

​响应式计算​​:所有统计信息通过计算属性实现,自动响应数据变化。

二、购物车页面组件实现

2.1 模板结构设计

<template>
  <div class="xtx-cart-page">
    <div class="container">
      <!-- 商品表格 -->
      <div class="cart">
        <table>
          <thead>
            <tr>
              <th><el-checkbox :model-value="cartStore.isAll" @change="allCheck"/></th>
              <th>商品信息</th>
              <th>单价</th>
              <th>数量</th>
              <th>小计</th>
              <th>操作</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="i in cartStore.cartList" :key="i.id">
              <td>
                <el-checkbox 
                  :model-value="i.selected" 
                  @change="(selected) => singleCheck(i, selected)" 
                />
              </td>
              <td>
                <RouterLink to="/">
                  <img :src="i.picture" alt="" />
                  <p class="name ellipsis">{{ i.name }}</p>
                </RouterLink>
              </td>
              <td>¥{{ i.price }}</td>
              <td><el-input-number v-model="i.count" /></td>
              <td>¥{{ (i.price * i.count).toFixed(2) }}</td>
              <td>
                <el-popconfirm @confirm="delCart(i)">
                  <template #reference><a>删除</a></template>
                </el-popconfirm>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      
      <!-- 底部操作栏 -->
      <div class="action">
        <div class="batch">
          共 {{ cartStore.allCount }} 件商品,合计:
          <span class="red">¥{{ cartStore.selectedPrice.toFixed(2) }}</span>
        </div>
        <el-button type="primary" size="large">下单结算</el-button>
      </div>
    </div>
  </div>
</template>

2.2 组件交互逻辑

<script setup>
import { useCartStore } from '@/store/cart'

const cartStore = useCartStore()

// 全选/取消全选
const allCheck = (selected) => {
  cartStore.allCheck(selected)
}

// 单个商品选择
const singleCheck = (item, selected) => {
  cartStore.singleCheck(item.skuId, selected)
}

// 删除商品
const delCart = (item) => {
  cartStore.delCart(item.skuId)
}
</script>

三、关键技术深度解析

3.1 数组方法的高级应用

​reduce - 数据聚合​

// 计算总数量
const allCount = computed(() => 
  cartList.value.reduce((a, b) => a + b.count, 0)
)

// 计算总金额
const allPrice = computed(() =>
  cartList.value.reduce((a, b) => a + b.count * b.price, 0)
)

​filter + reduce - 条件统计​

// 选中商品总金额
const selectedPrice = computed(() =>
  cartList.value
    .filter(item => item.selected)
    .reduce((a, b) => a + b.count * b.price, 0)
)

3.2 计算属性的性能优化

Vue 的计算属性具有缓存机制,只有依赖的响应式数据发生变化时才会重新计算:

const isAll = computed(() => 
  cartList.value.every(item => item.selected)
)

3.3 组件通信模式

​Props/Events 传统模式​​:父子组件通信

​Pinia 状态管理​​:跨组件状态共享

​provide/inject​​:深层组件通信

四、性能优化实践

4.1 列表渲染优化

<!-- 使用 key 属性提高 diff 算法效率 -->
<tr v-for="i in cartStore.cartList" :key="i.id">

4.2 计算属性拆分

// 不好的做法:复杂计算放在一个属性中
const complexData = computed(() => {
  // 大量计算逻辑...
})

// 推荐做法:拆分为多个计算属性
const filteredList = computed(() => /* ... */)
const sortedList = computed(() => /* ... */)
const finalResult = computed(() => /* ... */)

4.3 事件处理优化

// 使用防抖处理频繁事件
import { debounce } from 'lodash-es'

const updateCount = debounce((count) => {
  // 更新数量逻辑
}, 300)

五、最佳实践总结

5.1 代码组织原则

  1. ​单一职责​​:每个函数/组件只负责一个功能

  2. ​关注点分离​​:UI 渲染与业务逻辑分离

  3. ​响应式设计​​:合理使用 ref、reactive、computed

5.2 状态管理规范

  1. ​集中管理​​:全局状态统一在 store 中管理

  2. ​不可变更新​​:避免直接修改状态,使用函数式更新

  3. ​类型安全​​:配合 TypeScript 提高代码可靠性

5.3 用户体验优化

  1. ​加载状态​​:异步操作显示加载提示

  2. ​错误处理​​:友好的错误提示和重试机制

  3. ​空状态​​:优雅的空数据展示

六、完整项目结构

src/
├── store/
│   ├── cart.js          # 购物车状态管理
│   └── user.js          # 用户状态管理
├── components/
│   ├── CartItem.vue     # 购物车商品组件
│   └── CartSummary.vue  # 购物车统计组件
├── views/
│   └── Cart.vue         # 购物车页面
├── apis/
│   └── cart.js          # 购物车 API
└── utils/
    └── helpers.js       # 工具函数

结语

通过本文的详细讲解,我们完整实现了一个基于 Vue 3 技术栈的企业级购物车系统。这种架构不仅提供了良好的开发体验,还确保了应用的可维护性和扩展性。希望这篇技术博客对你在实际项目开发中有所启发和帮助。

​技术要点回顾​​:

  • Vue 3 Composition API 的现代化开发模式

  • Pinia 简化状态管理的优雅方案

  • Element Plus 组件库的高效使用

  • 响应式编程的最佳实践

在实际项目中,可以根据具体需求进一步扩展功能,如商品规格选择、优惠券计算、库存校验等,构建更加完善的电商购物体验。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐