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

如何基于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);

三、运行说明

  1. 启动后端服务器:node server.js
  2. 运行前端页面(建议用Live Server等工具,确保跨域请求正常)
  3. 测试添加商品、增减数量、查看购物车等功能

注意事项

  • 上述后端用JSON文件存储数据,重启服务器后数据保留,但生产环境需替换为数据库
  • 当前代码未区分用户,所有请求操作同一购物车,实际项目需结合用户登录(如JWT、Session)实现用户专属购物车
  • 可添加前端错误提示弹窗,提升用户体验

内容的提问来源于stack exchange,提问作者Freddy Leonardo Sosa Duran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 02:35:07