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

JS购物车开发:更新二维数组商品数量同步sessionStorage

问题描述
  • 需求:将下拉式购物车内的全量商品数据,传递到带结算功能的独立HTML购物车页面
  • 现有方案:将购物车详情存入二维数组,写入sessionStorage后在结算页读取展示
  • 现存bug:下拉购物车内用户修改后的最新商品数量,无法同步存入对应二维数组
  • 阻碍原因:quantityChanged()、updateCartTotal()、addItemToCart()分别绑定不同事件、逻辑独立,无法直接将用户输入的数量作为参数,传入负责写入sessionStorage的addItemToCart()函数

现有实现代码

/*Cart Funtion*/

/*Store items to cart*/

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

else {
  ready();
}

function ready() {
  var removeCartItemButtons = document.getElementsByClassName('cart-remove-btn')
  for (var i = 0; i < removeCartItemButtons.length; i++) {
      var button = removeCartItemButtons[i]
      button.addEventListener('click', removeCartItem)
  }

  var quantityInputs = document.getElementsByClassName('cart-quantity-input')
  for (var i = 0; i < quantityInputs.length; i++) {
      var input = quantityInputs[i]
      input.addEventListener('change', quantityChanged)
  }

  var addToCartButtons = document.getElementsByClassName('addCart_button');
  for (var i = 0; i < addToCartButtons.length; i++) {
    var button = addToCartButtons[i];
    button.addEventListener('click', addToCartClicked);
  }
}

function removeCartItem(event) {
  var buttonClicked = event.target
  buttonClicked.parentElement.parentElement.remove()
  updateCartTotal()
}

function quantityChanged(event) {
  var input = event.target
  if (isNaN(input.value) || input.value <= 0 || input.value % 1 != 0) {
      input.value = 1
  }
  updateCartTotal()
}

function updateCartTotal() {
  var cartItemContainer = document.getElementsByClassName('cart-items')[0]
  var cartRows = cartItemContainer.getElementsByClassName('cart-row')
  var subtotal = 0
  var total = 0
  for (var i = 0; i < cartRows.length; i++) {
      var cartRow = cartRows[i]
      var priceElement = cartRow.getElementsByClassName('cart-price')[0]
      var quantityElement = cartRow.getElementsByClassName('cart-quantity-input')[0]
      var price = parseFloat(priceElement.innerText.replace('RM', ''))
      var quantity = quantityElement.value
      subtotal = price * quantity
      total = total + (price * quantity)

      document.getElementsByClassName('cart-subtotal')[i].innerText = 'RM' + subtotal
  }
  
  total = Math.round(total * 100) / 100

  if (total % 1 != 0){
    document.getElementsByClassName('cart-total-price')[0].innerText = total 
  }

  else{
    document.getElementsByClassName('cart-total-price')[0].innerText = total+ '.00'
  }

  document.getElementsByClassName('label')[0].innerText = 'My Cart (' + cartRows.length +')'
}

var a=0;
var cartArray = [[]]

/*Add To Cart Funtion*/
function addToCartClicked(addCart) {
  var button = addCart.target;
  var shopItem = button.parentElement.parentElement;

  var imageSrc = shopItem.getElementsByClassName('item-img')[0].src;
  var title = shopItem.getElementsByClassName('item-title')[0].innerText;
  var price = shopItem.getElementsByClassName('item-price')[0].innerText;

  cartArray[a] = [imageSrc,title, price]
  a += 1
  console.log(cartArray)
  addItemToCart(imageSrc, title, price, cartArray);
  updateCartTotal();
}

var addItemId = 0;

function addItemToCart(imageSrc, title, price, cartArray) {
  //cart drop down
  var cartRow = document.createElement('div');
  cartRow.classList.add('cart-row')
  var cartItems = document.getElementsByClassName('cart-items')[0];
  var cartItemNames = cartItems.getElementsByClassName('cart-item-title');

  for (var i = 0; i < cartItemNames.length; i++){
    if (cartItemNames[i].innerText == title){
      alert('This package is already added to the cart.')
      return
    }
  }

  var cartRowContents = `
    <div class="cart-item cart-column">
    <span class="cart-item-title">${title}</span> 
    </div>
    <span class="cart-price cart-column">RM ${price}</span>
    <div class="cart-quantity cart-column">
      <input class="cart-quantity-input" type="number" value="1" min="1">
    </div>
    <span class="cart-subtotal cart-column">RM ${price}</span>
    <span class="cart-remove-btn cart-column"><i class="fa fa-trash" aria-hidden="true"></i></span>`

  cartRow.innerHTML = cartRowContents
  cartItems.append(cartRow)
  cartRow.getElementsByClassName('cart-remove-btn')[0].addEventListener('click',removeCartItem)
  cartRow.getElementsByClassName('cart-quantity-input')[0].addEventListener('change',quantityChanged)
  

  //saving the values in session storage  
  sessionStorage.setItem("productArray", JSON.stringify(cartArray));
}

效果参考截图

下拉式购物车运行效果
商品数量更新操作区域

解决方案

问题根源有两个:

  1. 存储的商品数组结构缺失数量字段,加购时只存了图、标题、价格,默认数量1没有写入数组
  2. 存储逻辑只在加购时触发一次,后续用户修改数量、删除商品时,没有同步更新数组和存储,靠全局索引变量维护数组很容易出现数据和页面对应不上的问题

不需要在各个独立函数之间传参,直接利用现有代码的逻辑特性改就行——所有购物车操作(加购、改数量、删商品)最后都会调用updateCartTotal(),直接把全量数据同步的逻辑放到这个函数最后,每次计算总价时遍历当前页面所有购物车行,重新收集最新的商品数据(包含用户改后的数量)再存到sessionStorage,完全不会有数据不同步的问题。

具体修改步骤:

  1. 删除全局无用代码:删掉var a=0;、var cartArray = [[]]、var addItemId = 0;这几个全局变量,后续数组在updateCartTotal()内部生成即可
  2. 修改addItemToCart()里的购物车渲染模板,补上商品图标签,否则后续收集数据时拿不到商品图地址,同时删掉函数末尾写sessionStorage的代码
  3. 重写updateCartTotal()函数,在遍历购物车行计算价格的同时,收集每一行的最新商品图、标题、价格、数量,生成最新的二维数组,计算完总价后统一写入sessionStorage
  4. 删掉addToCartClicked()里给cartArray赋值、递增索引a的冗余代码

修改后的核心代码:

// 重写后的updateCartTotal
function updateCartTotal() {
  var cartItemContainer = document.getElementsByClassName('cart-items')[0]
  var cartRows = cartItemContainer.getElementsByClassName('cart-row')
  var subtotal = 0
  var total = 0
  // 初始化空数组,每次重新收集最新数据
  var cartArray = []
  for (var i = 0; i < cartRows.length; i++) {
      var cartRow = cartRows[i]
      var priceElement = cartRow.getElementsByClassName('cart-price')[0]
      var quantityElement = cartRow.getElementsByClassName('cart-quantity-input')[0]
      var titleElement = cartRow.getElementsByClassName('cart-item-title')[0]
      var imgElement = cartRow.getElementsByClassName('cart-item-img')[0]

      var price = parseFloat(priceElement.innerText.replace('RM', ''))
      var quantity = parseInt(quantityElement.value)
      subtotal = price * quantity
      total = total + subtotal
      // 把当前行最新数据存入数组
      cartArray.push([imgElement.src, titleElement.innerText, price, quantity])

      document.getElementsByClassName('cart-subtotal')[i].innerText = 'RM' + subtotal
  }
  
  total = Math.round(total * 100) / 100
  document.getElementsByClassName('cart-total-price')[0].innerText = total % 1 != 0 ? total : total + '.00'
  document.getElementsByClassName('label')[0].innerText = 'My Cart (' + cartRows.length +')'

  // 统一写入最新数据到sessionStorage
  sessionStorage.setItem("productArray", JSON.stringify(cartArray));
}

// 简化后的addToCartClicked
function addToCartClicked(addCart) {
  var button = addCart.target;
  var shopItem = button.parentElement.parentElement;

  var imageSrc = shopItem.getElementsByClassName('item-img')[0].src;
  var title = shopItem.getElementsByClassName('item-title')[0].innerText;
  var price = shopItem.getElementsByClassName('item-price')[0].innerText.replace('RM', '');

  addItemToCart(imageSrc, title, price);
  updateCartTotal();
}

// 调整addItemToCart入参,去掉不需要传的cartArray,补上商品图渲染
function addItemToCart(imageSrc, title, price) {
  var cartRow = document.createElement('div');
  cartRow.classList.add('cart-row')
  var cartItems = document.getElementsByClassName('cart-items')[0];
  var cartItemNames = cartItems.getElementsByClassName('cart-item-title');

  for (var i = 0; i < cartItemNames.length; i++){
    if (cartItemNames[i].innerText == title){
      alert('This package is already added to the cart.')
      return
    }
  }

  var cartRowContents = `
    <div class="cart-item cart-column">
    <img class="cart-item-img" src="${imageSrc}" style="width:50px;height:50px;object-fit:cover;">
    <span class="cart-item-title">${title}</span> 
    </div>
    <span class="cart-price cart-column">RM ${price}</span>
    <div class="cart-quantity cart-column">
      <input class="cart-quantity-input" type="number" value="1" min="1">
    </div>
    <span class="cart-subtotal cart-column">RM ${price}</span>
    <span class="cart-remove-btn cart-column"><i class="fa fa-trash" aria-hidden="true"></i></span>`

  cartRow.innerHTML = cartRowContents
  cartItems.append(cartRow)
  cartRow.getElementsByClassName('cart-remove-btn')[0].addEventListener('click',removeCartItem)
  cartRow.getElementsByClassName('cart-quantity-input')[0].addEventListener('change',quantityChanged)
}

改完之后不管用户怎么调整商品数量、删除商品、加新商品,跳转到结算页前sessionStorage里存的永远是和下拉购物车显示完全一致的最新数据,结算页直接读取解析就能用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:39:34