如何基于Node.js实现购物车与后端服务器的交互?
改造前端购物车对接Node.js后端
一、Node.js后端搭建(基于Express)
1. 初始化项目
创建新的Node.js项目并安装依赖:
mkdir cart-backend && cd cart-backend npm init -y npm install express cors body-parser
2. 编写服务器代码(server.js)
用JSON文件临时存储购物车数据(生产环境建议替换为MongoDB/MySQL等数据库):
const express = require('express'); const cors = require('cors'); const bodyParser = require('body-parser'); const fs = require('fs'); const path = require('path'); const app = express(); const PORT = 3001; // 允许跨域请求(适配前端不同端口) app.use(cors()); app.use(bodyParser.json()); // 购物车数据存储路径 const CART_FILE = path.join(__dirname, 'cart.json'); // 初始化空购物车文件 if (!fs.existsSync(CART_FILE)) { fs.writeFileSync(CART_FILE, JSON.stringify([])); } // 读取购物车数据 const getCart = () => { const data = fs.readFileSync(CART_FILE, 'utf8'); return JSON.parse(data); }; // 保存购物车数据 const saveCart = (cart) => { fs.writeFileSync(CART_FILE, JSON.stringify(cart, null, 2)); }; // 1. 获取购物车数据 app.get('/api/cart', (req, res) => { const cart = getCart(); res.json(cart); }); // 2. 添加商品到购物车 app.post('/api/cart/add', (req, res) => { const { id, name, price, basePrice, image } = req.body; let cart = getCart(); // 检查商品是否已存在,存在则增加数量 const existingItemIndex = cart.findIndex(item => item.id === id); if (existingItemIndex !== -1) { cart[existingItemIndex].count += 1; cart[existingItemIndex].price = cart[existingItemIndex].basePrice * cart[existingItemIndex].count; } else { cart.push({ id, name, price: +price, basePrice: +basePrice, image, count: 1 }); } saveCart(cart); res.json(cart); }); // 3. 更新商品数量(增减) app.put('/api/cart/update', (req, res) => { const { id, action } = req.body; // action取值:'plus' / 'minus' let cart = getCart(); const itemIndex = cart.findIndex(item => item.id === id); if (itemIndex === -1) { return res.status(404).json({ message: '商品不存在' }); } if (action === 'plus') { cart[itemIndex].count += 1; } else if (action === 'minus') { cart[itemIndex].count -= 1; // 数量为0时移除商品 if (cart[itemIndex].count <= 0) { cart.splice(itemIndex, 1); } } // 更新商品总价(仅当商品未被移除时) if (cart[itemIndex]) { cart[itemIndex].price = cart[itemIndex].basePrice * cart[itemIndex].count; } saveCart(cart); res.json(cart); }); // 4. 删除购物车商品 app.delete('/api/cart/remove/:id', (req, res) => { const { id } = req.params; let cart = getCart(); cart = cart.filter(item => item.id !== id); saveCart(cart); res.json(cart); }); app.listen(PORT, () => { console.log(`服务器运行在 http://localhost:${PORT}`); });
二、前端代码改造
替换原localStorage逻辑,改为调用后端API:
1. 全局变量与核心函数修改
let productsInCart = []; const parentElement = document.querySelector('#buyItems'); const cartSumPrice = document.querySelector('#sum-prices'); const products = document.querySelectorAll('.product-under'); const API_BASE_URL = 'http://localhost:3001/api/cart'; // 计算购物车总价 const countTheSumPrice = () => { return productsInCart.reduce((sum, product) => sum + product.price, 0); }; // 从后端获取购物车数据并更新页面 const fetchCartAndUpdateHTML = async () => { try { const response = await fetch(API_BASE_URL); productsInCart = await response.json(); updateShoppingCartHTML(); } catch (error) { console.error('获取购物车失败:', error); } }; // 更新购物车页面展示 const updateShoppingCartHTML = () => { if (productsInCart.length > 0) { let result = productsInCart.map(product => { return ` <div class="cart-item"> <img src="${product.image}" alt="${product.name}" /> <div class="item-details"> <h5>${product.name}</h5> <p>$${product.price.toFixed(2)}</p> <div class="quantity-controls"> <button class="button-minus" data-id="${product.id}">-</button> <span>${product.count}</span> <button class="button-plus" data-id="${product.id}">+</button> </div> </div> </div> `; }); parentElement.innerHTML = result.join(''); document.querySelector('.checkout').classList.remove('hidden'); cartSumPrice.innerHTML = "$" + countTheSumPrice().toFixed(2); } else { document.querySelector('.checkout').classList.add('hidden'); parentElement.innerHTML = '<h4 class="empty">Your shopping cart is empty</h4>'; cartSumPrice.innerHTML = ""; } };
2. 添加商品逻辑修改
products.forEach(product => { product.addEventListener('click', async (e) => { if (e.target.classList.contains('addToCart')) { // 修复原代码拼写错误:prodcutID → productID const productID = e.target.dataset.productID; const productName = product.querySelector('.productName').innerHTML; const productPrice = product.querySelector('.priceValue').innerHTML; const productImage = product.querySelector('img').src; try { // 发送请求到后端添加商品 const response = await fetch(`${API_BASE_URL}/add`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: productID, name: productName, price: productPrice, basePrice: productPrice, image: productImage }) }); productsInCart = await response.json(); updateShoppingCartHTML(); } catch (error) { console.error('添加商品失败:', error); } } }); });
3. 数量增减按钮逻辑修改
parentElement.addEventListener('click', async (e) => { const isPlusButton = e.target.classList.contains('button-plus'); const isMinusButton = e.target.classList.contains('button-minus'); if (isPlusButton || isMinusButton) { const productID = e.target.dataset.id; const action = isPlusButton ? 'plus' : 'minus'; try { const response = await fetch(`${API_BASE_URL}/update`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: productID, action: action }) }); productsInCart = await response.json(); updateShoppingCartHTML(); } catch (error) { console.error('更新数量失败:', error); } } });
4. 页面初始化
// 页面加载时从后端拉取购物车数据 window.addEventListener('DOMContentLoaded', fetchCartAndUpdateHTML);
三、运行说明
- 启动后端服务器:
node server.js - 运行前端页面(建议用Live Server等工具,确保跨域请求正常)
- 测试添加商品、增减数量、查看购物车等功能
注意事项
- 上述后端用JSON文件存储数据,重启服务器后数据保留,但生产环境需替换为数据库
- 当前代码未区分用户,所有请求操作同一购物车,实际项目需结合用户登录(如JWT、Session)实现用户专属购物车
- 可添加前端错误提示弹窗,提升用户体验
内容的提问来源于stack exchange,提问作者Freddy Leonardo Sosa Duran
相关产品推荐
相关产品推荐

