用 localStorage 更稳妥。因其可持久化保存购物车数据,关闭页面后仍存在;而 sessionStorage 关闭标签页即清空,不适用于真实购物流程。

购物车数据用 localStorage 还是 sessionStorage?
用 localStorage 更稳妥。用户加完商品关掉页面再回来,购物车得还在;sessionStorage 一关 tab 就清空,不适合真实购物流程。
但要注意:直接存对象会出错——localStorage.setItem('cart', {id: 1, qty: 2}) 会报 TypeError: Converting circular structure to JSON(如果对象里有函数或循环引用),更常见的是静默失败(存进去是 [object Object])。
- 必须用
JSON.stringify()存,JSON.parse()取 - 存之前先判空:
if (!cartItems) cartItems = [],避免parse(null)报错 - 每次修改后立刻写回:
localStorage.setItem('cart', JSON.stringify(cartItems)),别攒着批量写
点击“加入购物车”按钮没反应?检查事件绑定时机
常见原因是 DOM 还没加载完就执行了 JS 绑定,比如把 document.querySelector('.add-btn').addEventListener(...) 写在 <script> 标签顶部,而按钮在下方 HTML 里。
解决方法不是加 setTimeout,而是:
立即学习“前端免费学习笔记(深入)”;
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 把
<script>放在</body>前面 - 或者用
DOMContentLoaded包一层:document.addEventListener('DOMContentLoaded', () => { document.querySelectorAll('.add-btn').forEach(btn => { btn.addEventListener('click', addToCart) }) }) - 别用
onclick="addToCart()"内联写法——调试难、逻辑散、无法传参(如商品 ID)
购物车列表渲染后数量不更新?小心 innerHTML 覆盖事件监听器
很多教程用 cartContainer.innerHTML = htmlString 重绘整个列表,这会把之前绑在每个“减数量”按钮上的 click 事件全干掉——按钮看着还在,点不了。
正确做法是只更新变动部分:
- 用
document.querySelector(`[data-id="${id}"] .qty-display`).textContent = newQty更新数字 - 用
document.querySelector(`[data-id="${id}"] .price-line`).textContent = total.toFixed(2)更新小计 - 真要重绘整块,得重新绑定事件,或改用事件委托:
cartContainer.addEventListener('click', e => { if (e.target.classList.contains('btn-dec')) { const id = e.target.closest('[data-id]').dataset.id updateQuantity(id, -1) } })
移动端点击“+”“−”按钮延迟高?避免频繁触发 reflow
每次改数量都调 innerHTML 或反复 appendChild,浏览器要重排重绘,手指点下去卡顿明显。
关键优化点:
- 所有数量变更统一走一个
renderCartItem(item)函数,只更新对应 DOM 节点的文本内容,不动结构 - 价格计算用
Number(item.price) * item.qty,别用parseFloat()——后者对"19.99000"这类字符串容易丢精度 - 总金额用
cartItems.reduce((sum, item) => sum + item.price * item.qty, 0).toFixed(2),别在循环里累加再toFixed,否则浮点误差放大
真实项目里,购物车远不止显示和增减——库存校验、登录态同步、优惠券联动,都是后面才踩到的坑。先跑通本地存取和响应式渲染,比堆 CSS 动画重要得多。


















