用vue.js写一个购物车

admin 104 0
基于Vue.js开发的购物车应用,利用其响应式数据特性实现商品管理核心功能,通过data选项存储商品列表(含id、名称、价格、数量等属性),methods定义添加商品、增减数量、删除商品等操作方法,computed计算属性实时动态统计商品总数量及总金额,采用组件化拆分,将商品项封装为独立子组件,提升代码复用性,结合v-for指令渲染商品列表,v-model绑定数量输入,事件处理实现交互逻辑,同时可集成localStorage实现购物车数据持久化,刷新页面后数据不丢失,整体实现简洁高效,依赖Vue的响应式机制,确保数据变化时视图自动更新,提升用户体验。

Vue.js实战:构建一个功能完整的购物车应用

在电商和各类在线服务中,购物车作为用户与商品交互的核心模块,其功能完整性、交互流畅性直接影响用户体验,Vue.js凭借其响应式数据绑定组件化开发简洁的API,成为构建动态购物车应用的理想选择,本文将以Vue 3为基础,结合组合式API,一步步实现一个包含商品展示、添加/删除商品、数量调整、价格计算等核心功能的购物车应用,并探讨状态管理和功能扩展的思路。

项目准备

技术栈

  • 前端框架:Vue 3(组合式API)
  • 构建工具:Vite(快速初始化项目)
  • 状态管理:Pinia(Vue 3官方推荐,替代Vuex)
  • 样式处理:CSS(或预处理器如SCSS,本文以原生CSS为例)
  • 开发工具:VS Code(推荐安装Volar和ESLint插件)

初始化项目

使用Vite创建Vue 3项目:

npm create vite@latest vue-shopping-cart -- --template vue
cd vue-shopping-cart
npm install

安装Pinia:

npm install pinia

main.js中初始化Pinia:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import './assets/main.css' // 导入全局样式
const app = createApp(App)
app.use(createPinia())
app.mount('#app')

核心功能实现

商品列表展示

我们需要模拟商品数据并展示在页面上。

商品数据定义

src/data/products.js中模拟商品列表:

export const products = [
  { 
    id: 1, 
    name: 'Vue.js实战书籍', 
    price: 89, 
    image: 'https://via.placeholder.com/150',
    description: '深入浅出Vue.js开发技巧与实践'
  },
  { 
    id: 2, 
    name: 'Node.js权威指南', 
    price: 129, 
    image: 'https://via.placeholder.com/150',
    description: 'Node.js全栈开发权威指南'
  },
  { 
    id: 3, 
    name: 'JavaScript高级程序设计', 
    price: 99, 
    image: 'https://via.placeholder.com/150',
    description: '前端开发必读经典'
  },
  { 
    id: 4, 
    name: 'CSS权威指南', 
    price: 79, 
    image: 'https://via.placeholder.com/150',
    description: 'CSS布局与设计技巧大全'
  },
]
商品列表组件

创建src/components/ProductList.vue,展示商品并支持"加入购物车":

<template>
  <div class="product-list">
    <h2>商品列表</h2>
    <div class="products">
      <div v-for="product in products" :key="product.id" class="product-card">
        <img :src="product.image" :alt="product.name" class="product-image" />
        <h3>{{ product.name }}</h3>
        <p class="description">{{ product.description }}</p>
        <p class="price">¥{{ product.price }}</p>
        <button @click="addToCart(product)">加入购物车</button>
      </div>
    </div>
  </div>
</template>
<script setup>
import { products } from '../data/products'
import { useCartStore } from '../stores/cart'
import { toast } from 'vue3-toastify'
import 'vue3-toastify/dist/index.css'
const cartStore = useCartStore()
const addToCart = (product) => {
  cartStore.addItem(product)
  toast.success(`${product.name} 已加入购物车`, {
    autoClose: 2000,
    position: 'top-right'
  })
}
</script>
<style scoped>
.product-list {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}
.products {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 25px;
}
.product-card {
  border: 1px solid #e0e0e0;
  border-radius: 12px;
  padding: 20px;
  text-align: center;
  background: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s, box-shadow 0.3s;
}
.product-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
}
.product-image {
  width: 100%;
  height: 180px;
  object-fit: cover;
  border-radius: 8px;
  margin-bottom: 15px;
}
h3 {
  font-size: 1.2rem;
  margin: 10px 0;
  color: #333;
}
.description {
  color: #666;
  font-size: 0.9rem;
  margin: 8px 0;
  height: 40px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.price {
  color: #e74c3c;
  font-weight: bold;
  font-size: 1.1rem;
  margin: 12px 0;
}
button {
  background: #3498db;
  color: white;
  border: none;
  padding: 10px 20px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.3s, transform 0.2s;
  font-weight: 500;
}
button:hover {
  background: #2980b9;
  transform: scale(1.05);
}
button:active {
  transform: scale(0.98);
}
</style>

购物车状态管理(Pinia)

购物车的数据(如商品列表、总价)需要跨组件共享,使用Pinia可以集中管理状态。

创建Pinia Store

src/stores/cart.js中定义购物车状态:

import { defineStore } from 'pinia'
export const useCartStore = defineStore('cart', {
  state: () => ({
    items: [], // 购物车商品:{ id, name, price, quantity, image }
  }),
  getters: {
    // 计算购物车总商品数量
    totalItems: (state) => state.items.reduce((sum, item) => sum + item.quantity, 0),
    // 计算购物车总价
    totalPrice: (state) => state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
    // 检查商品是否已在购物车中
    isInCart: (state) => (productId) => {
      return state.items.some(item => item.id === productId)
    },
    // 获取购物车中特定商品的数量
    getItemQuantity: (state) => (productId) => {
      const item = state.items.find(item => item.id === productId)
      return item ? item.quantity : 0
    }
  },
  actions: {
    // 添加商品到购物车
    addItem(product) {
      const existingItem = this.items.find(item => item.id === product.id)
      if (existingItem) {
        // 如果商品已存在,增加数量
        existingItem.quantity++
      } else {
        // 如果商品不存在,添加新项
        this.items.push({
          ...product,
          quantity: 1
        })
      }
    },
    // 从购物车移除商品
    removeItem(productId) {
      const

标签: #js #购物车 #前端 #电商