如何用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
相关产品推荐
相关产品推荐

