如何同步 UI 与虚拟购物车的变化?

How to sync UI with changes in virtual cart?

我正在学习一些前端设计模式,我一直在阅读关于如何在购物车示例中创建虚拟购物车,然后让 UI 监听它的变化,然后反映在页面上。但是我还没有找到很好的例子来说明如何“监听变化并反映它”,特别是在我基本上在多个地方同步变化的地方。

下面我尝试了一个最基本的系统。代码工作(fiddle here),但是,它看起来非常脆弱(特别是因为现实可能比这复杂得多,需要匹配更多的东西才能找到正确的购物车行。例如,changePriceInUIremoveFromUI 函数依赖于匹配器,因为我了解到 item.row 只能在购物车页面或总计页面中引用 1 个 jQuery 对象。那是为什么被注释掉的代码,如果使用,只会影响 Total pagecart-body 上的 UI。但被注释掉的代码对我来说最有意义准确处理购物车中的商品并同步更改。

例如,我可以想象商品是 Class,每次价格更改时,都会有一个 setter 函数更新 UI(但同样,item.row 只有 1 行)。但我想不是吗?很想知道如何构建购物车来同步更改。欢迎其他学习资源!

cart = []
cart_body = $(".cart-body")

function addItem(name, price) {
  item = {}
  item.name = name
  item.price = price  
  item.row = $("<tr class='item-row' data-name='"+name+"' data-price='"+price+"'><td class='name'>" + name + "</td><td class='price'>" + price + "</td></tr>")
  cart.push(item)
  addToUI(item.row)
}

function addToUI(item_row) {
  cart_body.append(item_row)
}

function removeItem(name,price) {
  var length = cart.length
    for (var i = 0; i < length; i++ ) {
    if (cart[i].name == name && cart[i].price == price) { 
      item_whose_row_to_remove = cart[i]
      cart.splice(i,1)
      break
    }
  }
  removeFromUI(item_whose_row_to_remove)
}

function removeFromUI(item) {
  // item.row.remove()
  cart_body.find(".item-row[data-name='"+item.name+"'][data-price='"+item.price+"']").remove()
}

function changeItemPrice(name,new_price) {
  var length = cart.length
    for (var i = 0; i < length; i++ ) {
    if (cart[i].name == name) { 
      old_price = cart[i].price
      cart[i].price = new_price
      item_whose_price_to_update = cart[i]
      break
    }
  }
  changePriceInUI(item_whose_price_to_update, old_price)
}

function changePriceInUI(item, old_price) {
  // item.row.find(".price").empty().append(item.price)
  cart_body.find(".item-row[data-name='"+item.name+"'][data-price='"+old_price+"']").find(".price").empty().append(item.price)
}


addItem("Ball", 1)
addItem("Stick",2)
removeItem("Ball",1)
changeItemPrice("Stick",3)

这是一个例子:https://jsfiddle.net/4tq9a6h3/

我创建了一个 ShoppingCart class,它拥有对 HTML table 的引用,以及一组购物车项目。每当您调用 addItem 方法将商品添加到购物车时,class 会在内部处理更新 HTML table。 UI 永远不会与 cartItems 数组不同步,因为 cartItems 数组是 UI 更新所基于的“主要真实来源”之后,当数组内容改变时。

请注意,这缺少很多优化和功能。通常你不会清空整个 HTML table 例如简单地添加一个新项目,因为没有理由这样做,因为现有的 table 行将与现有数组相同元素。

与 addItem 的工作方式类似,您可以实施 removeItem 和 changePrice 方法,最后再次调用 this.render()

其次请注意,自己编写这样的代码用于生产可能不是一个好主意,有更好的方法。这个例子是为了回答你的问题,关于你如何虚拟地解耦数据和 UI 并在数据更新时更新 UI (以及如何不依赖 HTML 元素当你'我想查看用户在购物车中有哪些商品 - 您只需检查 cartItems 数组包含的内容,而不是读取 HTML table 行)。另一个重要的事情是 cartItems-array 是一切的中心。 UI 的每次更新都是通过 反映 cartItems 数组包含的内容来完成的,而不是相反。

此外,可能还可以利用 Custom Events,以便在 cartItems-array 更改后触发 UI 更新(调用 render 方法),而不必记住“手动”调用它.

要求的补充:https://jsfiddle.net/qr0avhwe/2/