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

如何用JavaScript localStorage实现跨页面保留购物车商品

购物车持久化存储解决方案

问题

开发购物车功能时遇到如下问题:将商品添加至购物车后,切换页面时购物车内的商品会被清空。需要借助localStorage实现购物车商品的持久化存储,使得切换页面后仍能继续添加商品,且原有商品不会丢失。

解决方案

核心思路

通过localStorage存储购物车的结构化数据(包含商品标题、价格、库存、图片、数量),在页面加载时从localStorage读取数据渲染购物车,每次购物车数据变化(添加、删除、修改数量)时同步更新localStorage。

修改后完整代码

// cart
let cartIcon = document.querySelector('#add-to-cart');
let cart = document.querySelector('.cart');
let closeCart = document.querySelector('#close-cart');
let buttons = document.querySelector('.btn-buy');

// open cart
cartIcon.onclick = () => {
  cart.classList.add('active');
};
// close cart
closeCart.onclick = () => {
  cart.classList.remove('active');
};

// 封装localStorage操作函数
function getCartItems() {
  return JSON.parse(localStorage.getItem('cartItems')) || [];
}

function saveCartItems(items) {
  localStorage.setItem('cartItems', JSON.stringify(items));
}

// 从localStorage恢复购物车到页面
function renderCartFromStorage() {
  let cartItems = getCartItems();
  let cartContent = document.getElementsByClassName('cart-content')[0];
  
  cartItems.forEach(item => {
    addProductToCart(item.title, item.price, item.stock, item.productImg, item.quantity);
  });
  updateTotal();
}

if (document.readyState == 'loading') {
  document.addEventListener('DOMContentLoaded', ready)
} else {
  ready();
}

function ready() {
  // 页面加载时恢复购物车
  renderCartFromStorage();

  //Remove item from cart
  let removeCartButtons = document.getElementsByClassName('cart-remove');
  console.log(removeCartButtons);
  for (let i = 0; i < removeCartButtons.length; i++) {
    let button = removeCartButtons[i];
    button.addEventListener("click", removeCartItem);
  }
  //quantity changes
  let quantityInputs = document.getElementsByClassName('cart-quantity');
  for (let i = 0; i < quantityInputs.length; i++) {
    let input = quantityInputs[i];
    input.addEventListener("change", quantityChanged);
  }
  // add to cart
  let addCart = document.getElementsByClassName('add-cart');
  for (let i = 0; i < addCart.length; i++) {
    let button = addCart[i];
    button.addEventListener('click', addCartClicked);
  }

  let addCarts = document.getElementsByClassName('add-cart2'); 
  for (let i = 0; i < addCarts.length; i++) {
    let button = addCarts[i];
    button.addEventListener('click', addCartsClicked);
  } 
  
  buttons.classList.add('hide-btn');
  document.getElementsByClassName('btn-buy')[0]
  .addEventListener('click', buyButtonClicked);
  
  document.getElementsByClassName('clear-cart')[0]
  .addEventListener('click', clearButtonClicked);

}

function showBuyButton(total) {
  if (total > 0) {
    buttons.classList.remove('hide-btn');
  } else {
    buttons.classList.add('hide-btn');
  }
}

function buyButtonClicked() {
  let cartContent = document.getElementsByClassName('cart-content')[0];
  while (cartContent.hasChildNodes()) {
    cartContent.removeChild(cartContent.firstChild);
  }
  // 下单后清空localStorage
  saveCartItems([]);
  alert("Your order is placed");
  updateTotal();
}

function clearButtonClicked() {
  let cartButtonClicked = document.getElementsByClassName('cart-content')[0];
  while (cartButtonClicked.hasChildNodes()) {
    cartButtonClicked.removeChild(cartButtonClicked.firstChild);
  }
  // 清空购物车后同步localStorage
  saveCartItems([]);
  updateTotal();
}

//Remove item from cart
function removeCartItem(event) {
  let buttonClicked = event.target;
  let cartBox = buttonClicked.parentElement;
  let title = cartBox.getElementsByClassName('cart-product-title')[0].innerText;
  
  // 从localStorage移除对应商品
  let cartItems = getCartItems();
  cartItems = cartItems.filter(item => item.title !== title);
  saveCartItems(cartItems);
  
  cartBox.remove();
  updateTotal();  
}

//quantity change
function quantityChanged(event) {
  let input = event.target;
  if (isNaN(input.value) || input.value <= 0) {
    input.value = 1;
  }
  if (isNaN(input.value) || input.value > 20) {
    alert('Max items are 20');
    input.value = 20;
  }
  
  // 同步更新localStorage中的数量
  let cartBox = input.closest('.cart-box');
  let title = cartBox.getElementsByClassName('cart-product-title')[0].innerText;
  let cartItems = getCartItems();
  cartItems.forEach(item => {
    if (item.title === title) {
      item.quantity = parseInt(input.value);
    }
  });
  saveCartItems(cartItems);
  
  updateTotal();
}

function addCartClicked(event) {
  let button = event.target;
  let shopProducts = button.parentElement;
  let title = shopProducts.getElementsByClassName('product-name')[0].innerText;
  let price = shopProducts.getElementsByClassName('product-price')[0].innerText;
  let stock = shopProducts.getElementsByClassName('product-stock')[0].innerText;
  let productImg = shopProducts.getElementsByClassName('product-picture')[0].src;
  console.log(title, price, stock, productImg);
  
  // 先检查localStorage中是否已存在该商品
  let cartItems = getCartItems();
  let existingItem = cartItems.find(item => item.title === title);
  if (existingItem) {
    alert("You have already add this item to cart");
    return;
  }
  
  addProductToCart(title, price, stock, productImg, 1);
  // 添加到localStorage
  cartItems.push({
    title,
    price,
    stock,
    productImg,
    quantity: 1
  });
  saveCartItems(cartItems);
  
  updateTotal();
}

// 扩展addProductToCart函数,支持传入数量
function addProductToCart(title, price, stock, productImg, quantity = 1) {
  let cartShopBox = document.createElement('div');
  cartShopBox.classList.add('cart-box');  
  let cartItems = document.getElementsByClassName('cart-content')[0];
  
  let cartBoxContent = `
    <img src="${productImg }" alt="" class="cart-img">
    <div class="detail-box">
      <div class="cart-product-title">${title}</div>
      <div class="cart-price">${price}</div>
      <div class="cart-stock">${stock}</div>
      <input type="number" value="${quantity}" class="cart-quantity">
    </div>
    <i class='bx bx-trash cart-remove'></i>`;

  cartShopBox.innerHTML = cartBoxContent;
  cartItems.append(cartShopBox);
  cartShopBox
    .getElementsByClassName('cart-remove')[0]
    .addEventListener('click', removeCartItem);
  cartShopBox
    .getElementsByClassName('cart-quantity')[0]
    .addEventListener('change', quantityChanged);
}

//update total
function updateTotal() {
  let cartContent = document.getElementsByClassName('cart-content')[0];
  let cartBoxes = cartContent.getElementsByClassName('cart-box');
  let total = 0;
  for (let i = 0; i < cartBoxes.length; i++) {
    let cartBox = cartBoxes[i];
    let priceElement = cartBox.getElementsByClassName('cart-price')[0];
    let quantityElement = cartBox.getElementsByClassName('cart-quantity')[0];
    let price = parseFloat(priceElement.innerText.replace("$",""));
    let quantity = quantityElement.value;
    total = total + (price * quantity);
  }
  //if price contains some cents
  total = Math.round(total *100) / 100;
  document.getElementsByClassName('total-price')[0].innerText = "$" + total;
  showBuyButton(total);
}

// 补充addCartsClicked函数逻辑,同步localStorage
function addCartsClicked(event) {
  let button = event.target;
  let shopProducts = button.parentElement;
  let title = shopProducts.getElementsByClassName('product-name')[0].innerText;
  let price = shopProducts.getElementsByClassName('product-price')[0].innerText;
  let stock = shopProducts.getElementsByClassName('product-stock')[0].innerText;
  let productImg = shopProducts.getElementsByClassName('product-picture')[0].src;
  
  let cartItems = getCartItems();
  let existingItem = cartItems.find(item => item.title === title);
  if (existingItem) {
    alert("You have already add this item to cart");
    return;
  }
  
  addProductToCart(title, price, stock, productImg, 1);
  cartItems.push({
    title,
    price,
    stock,
    productImg,
    quantity: 1
  });
  saveCartItems(cartItems);
  
  updateTotal();
}

function nameS() {
  let name = document.getElementById('nameS').value;
}

关键修改说明

  • 新增getCartItems和saveCartItems函数,统一处理localStorage的读写操作
  • 新增renderCartFromStorage函数,页面加载时从localStorage恢复购物车商品
  • 修改addCartClicked并补充addCartsClicked函数,添加商品前检查localStorage,添加后同步保存数据
  • 修改removeCartItem函数,删除商品时同步移除localStorage中的对应条目
  • 修改quantityChanged函数,数量变化时同步更新localStorage中的对应商品数量
  • 修改buyButtonClicked和clearButtonClicked函数,清空购物车时同步清空localStorage
  • 扩展addProductToCart函数,支持传入初始数量,适配从localStorage恢复商品的场景

内容的提问来源于stack exchange,提问作者whseven7

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:07:04