使用JavaScript实现购物车商品渲染 解决多商品无法循环展示问题
问题根源
你的代码核心问题出在addCartItem方法的逻辑上:
- 每次点击添加按钮时,你遍历了全部商品数组来生成购物车项DOM,循环赋值
div.innerHTML会覆盖之前的内容,最终只显示最后一个商品的信息 - 没有根据点击按钮的
data-id筛选对应要添加的商品,也没有把选中商品存入提前声明的cart数组统一管理 - 没有给商品初始化
amount字段,渲染时会出现undefined的问题 - 原有代码里存在HTML转义符错误,
</>无法正常渲染DOM结构
修复后的完整代码
const cartBtn = document.querySelector(`.cart-btn`); const closeCartBtn = document.querySelector(`.close-cart`); const clearCartBtn = document.querySelector(`.clear-cart`); const cartDOM = document.querySelector(".cart"); const cartOverlay = document.querySelector(`.cart-overlay`); const cartItems = document.querySelector(".cart-items"); const cartTotal = document.querySelector(".cart-total"); const cartContent = document.querySelector(".cart-content"); const productsDOM = document.querySelector(`.products`); let cart = []; // 购物车数组 let buttonsDOM = []; // 按钮数组 // 商品数据 let itemObject = [{ title: "Chocolate", price: 10.99, id: 1, img: "https://images.pexels.com/photos/1055272/pexels-photo-1055272.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260" }, { title: "Cream", price: 12.99, id: 2, img: "https://images.pexels.com/photos/1055270/pexels-photo-1055270.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260" }, { title: "Frosting", price: 12.99, id: 3, img: "https://images.pexels.com/photos/1055271/pexels-photo-1055271.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260" }, { title: "Berry", price: 14.99, id: 4, img: "https://images.pexels.com/photos/3081657/pexels-photo-3081657.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260" }, { title: "Deluxe", price: 19.99, id: 5, img: "https://images.pexels.com/photos/1998634/pexels-photo-1998634.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260" }, { title: "Oreo", price: 14.99, id: 6, img: "https://images.pexels.com/photos/783274/pexels-photo-783274.jpeg?auto=compress&cs=tinysrgb&h=750&w=1260" }]; // 点击打开购物车 cartBtn.addEventListener(`click`, () => { cartOverlay.classList.remove(`invisible`); }); // 隐藏购物车遮罩 function hideOverlay() { cartOverlay.classList.add(`invisible`); } // 点击关闭购物车 closeCartBtn.addEventListener(`click`, () => { cartOverlay.classList.add(`invisible`); }); // 清空购物车并隐藏遮罩 clearCartBtn.addEventListener(`click`, () => { cart = []; cartContent.innerHTML = ''; updateCartTotal(); // 重置所有按钮状态 buttonsDOM.forEach(btn => { btn.innerText = "Purchase"; btn.disabled = false; }); hideOverlay(); }); // 删除单个购物车商品 function deleteSingleItem(id) { cart = cart.filter(item => item.id !== id); renderCart(); // 恢复对应按钮状态 const targetBtn = buttonsDOM.find(btn => btn.dataset.id == id); if(targetBtn) { targetBtn.innerText = "Purchase"; targetBtn.disabled = false; } updateCartTotal(); } // 更新购物车总价和商品数量 function updateCartTotal() { let total = 0; let count = 0; cart.forEach(item => { total += item.price * item.amount; count += item.amount; }); cartTotal.innerText = total.toFixed(2); cartItems.innerText = count; } // 渲染整个购物车 function renderCart() { cartContent.innerHTML = ''; cart.forEach(item => { const div = document.createElement('div'); div.classList.add('cart-item'); div.innerHTML = ` <div class="grid align-middle grid-cols-3 gap-2 my-4"> <img class="h-28 w-28" src="${item.img}" alt="Product"/> <div> <h4>${item.title}</h4> <h5>$${item.price}</h5> <span class="text-red-200 remove-btn" data-id=${item.id}>Remove</span> </div> <div> <i class="fas fa-chevron-up text-red-200 align-middle increase-btn" data-id=${item.id}></i> <p class="align-middle item-amount">${item.amount}</p> <i class="fas fa-chevron-down text-red-200 align-middle decrease-btn" data-id=${item.id}></i> </div> </div>`; cartContent.appendChild(div); }); // 绑定删除、增减数量事件 bindCartItemEvents(); updateCartTotal(); } // 绑定购物车内商品的操作事件 function bindCartItemEvents() { // 删除事件 document.querySelectorAll('.remove-btn').forEach(btn => { btn.addEventListener('click', e => { const id = e.target.dataset.id; deleteSingleItem(id); }); }); // 增加数量 document.querySelectorAll('.increase-btn').forEach(btn => { btn.addEventListener('click', e => { const id = e.target.dataset.id; const targetItem = cart.find(item => item.id == id); targetItem.amount++; renderCart(); }); }); // 减少数量 document.querySelectorAll('.decrease-btn').forEach(btn => { btn.addEventListener('click', e => { const id = e.target.dataset.id; const targetItem = cart.find(item => item.id == id); if(targetItem.amount > 1) { targetItem.amount--; renderCart(); } else { deleteSingleItem(id); } }); }); } // 渲染商品列表 function displayProducts() { let html = ``; itemObject.forEach((item) => { html += ` <div class="bg-white rounded-lg"> <img class="rounded-md w-screen object-cover max-h-60" src="${item.img}" alt=""> <div class="py-2 px-8 text-gray-600"> <div class="grid grid-cols-2 py-3 text-xl font-bold "> <h3>${item.title}</h3> <p class="text-right">$${item.price}</p> </div> <button data-id=${item.id} class="bg-purple-200 font-bold px-3 mt-2 text-xl py-4 mb-4 w-full rounded-md transition-all hover:bg-purple-300 bag-btn">Purchase</button> </div> </div> `; }); productsDOM.innerHTML = html; } // 绑定商品添加到购物车的事件 function addProductsToCart() { const buttons = [...document.querySelectorAll(`.bag-btn`)]; buttonsDOM = buttons; buttons.forEach(button => { let id = button.dataset.id; let inCart = cart.find(item => item.id == id); if (inCart) { button.innerText = "In Cart"; button.disabled = true; } button.addEventListener(`click`, event => { event.target.innerText = "In Cart"; event.target.disabled = true; // 找到当前点击的商品 const currentItem = {...itemObject.find(item => item.id == id)}; // 初始化购买数量 currentItem.amount = 1; // 加入购物车数组 cart.push(currentItem); // 重新渲染购物车 renderCart(); // 打开购物车 cartOverlay.classList.remove(`invisible`); }); }); } displayProducts(); addProductsToCart();
补充说明
现在代码已经支持多商品添加、商品数量增减、单个商品删除、购物车清空、总价自动计算的完整功能,所有操作都会同步更新按钮状态和购物车数据。
内容的提问来源于stack exchange,提问作者OrangeSoLlama
相关产品推荐
相关产品推荐

