简体   繁体   English

如何将产品项目添加到购物车以及如何在始终(重新)计算购物车项目的总价的同时将其从那里删除?

[英]How does one add a product-item to a shopping-cart and how would one remove it from there while always (re)calculating the cart items' total price?

The following array features objects which are the product items.以下数组具有作为产品项目的对象。 Clicking at the Add to cart button should render the related item into a table presentation via the mytable function as shown further below.单击“ Add to cart按钮应通过mytable函数将相关项目呈现为表格演示,如下所示。

var product = [
  {"name":"jeans","image":"pics/jeans3.jpg","price":500},
  {"name":"hoodie","image":"pics/hoodie.jpg","price":700},
  {"name":"shirt","image":"pics/shirt.jpg","price":450},
  {"name":"sweter","image":"pics/sweter.jpg","price":1100},
  {"name":"trouser","image":"pics/trouser.jpg","price":600},
  {"name":"tshirt","image":"pics/tshirt.jpg","price":250}
];

Here is the loop which is supposed to create the product overview (event handling inclusive) from the above provided data.这是应该从上面提供的数据创建产品概述(包括事件处理)的循环。

var head = "<div id='main'>";

for (var i in product) {
  head += "<div class='pro'>";
  head += "<h1>" + product[i].name + "</h1>";
  head += "<img src=" + product[i].image + ">";
  head += "<p>" + product[i].price + "</p>";
  head += "<button onclick='mytable(i)'>Add to cart</button>"
  head += "</div>";
}

And here is the rest of the above code which is expected to write the product overview to the document.这是上面代码的其余部分,预计将产品概述写入文档。 There is also the above mentioned mytable function which is supposed to create an items shopping cart presentation (event handling inclusive).还有上面提到的mytable函数,它应该创建一个商品购物车展示(包括事件处理)。

head += "</div>";
head += "<div id='cart'> </div>"
document.write(head);

function mytable(i) {
     document.getElementById('cart').innerHTML = "<table border='1'> <tr><th>Product name</th>  <th>Quantity</th>  <th>Price</th> <th>image</th><th><button>Remove Items</button></th></tr></table>";
} 

Additionally I want to handle the removal of a cart item.另外我想处理购物车项目的删除。 For both cases adding and removing items to/from the cart I want to calculate the total price of all cart items.对于在购物车中添加和删除商品的两种情况,我想计算所有购物车商品的总价。

How could one achieve this?怎么能做到这一点?

Techniques being used ...正在使用的技术...

Web Api网络接口

Event delegation事件委托

Syntax句法

Expressions and operators 表达式和运算符

JavaScript Api / Methods of Standard built-in objects JavaScript Api / 标准内置对象的方法

 const productList = [ { pid: "abcd-0987-WXYZ", name: "jeans", price: 500, image: "https://media.istockphoto.com/photos/blue-denim-picture-id501250332" }, { pid: "efgh-1234-QRST", name: "hoodie", price: 700, image: "https://media.istockphoto.com/photos/faceless-man-in-hoodie-standing-isolated-on-black-picture-id916306960" }, { pid: "ijkl-6543-MNOP", name: "shirt", price: 450, image: "https://media.istockphoto.com/photos/men-shirt-for-clothing-isolated-on-white-background-picture-id641319368" }, { pid: "mnop-5678-IJKL", name: "sweater", price: 1100, image: "https://media.istockphoto.com/photos/minimalistic-rustic-composition-with-stacked-vintage-knitted-easy-picture-id1049751604" }, { pid: "qrst-2109-EFGH", name: "trouser", price: 600, image: "https://media.istockphoto.com/photos/pants-picture-id168790494" }, { pid: "wxyz-9012-ABCD", name: "tshirt", price: 250, image: "https://media.istockphoto.com/photos/close-up-of-colorful-tshirts-on-hangers-apparel-background-picture-id1170635789" }, ]; function createElementFromMarkup(html) { const renderBox = document.createElement('div'); renderBox.innerHTML = html; return renderBox.firstElementChild; } function createItemMainView(data) { return createElementFromMarkup(` <li data-pid="${ data.pid }"> <h3>${ data.name }</h3> <img src="${ data.image }"/> <dl><dt>Price</dt><dd>${ data.price }</dd></dl> <button data-add-pid="${ data.pid }" data-text="Add to cart">Add to cart</button> </li> `); } function createItemCartView(data) { return createElementFromMarkup(` <li data-pid="${ data.pid }"> <h3>${ data.name }</h3> <dl><dt>Price</dt><dd>${ data.price }</dd></dl> <button data-remove-pid="${ data.pid }">Remove</button> </li> `); } function createShoppingItem(data) { return { data, view: { main: createItemMainView(data), cart: createItemCartView(data), }, checkout: { isInCart: false, orderCount: 0, }, }; } function scrollIntoViewIfNeeded(elmNode) { if (elmNode) { const whichScrollIntoView = elmNode.scrollIntoViewIfNeeded ? 'scrollIntoViewIfNeeded' : 'scrollIntoView'; elmNode[whichScrollIntoView](); } } function updateShoppingCartTotal(elmCartTotal, shoppingState) { const total = Object .values(shoppingState) .reduce((sum, item) => (sum + ((item.data.price ?? 0) * (item.checkout.orderCount ?? 0))), 0 ); elmCartTotal.textContent = (total === 0) ? '' : total; } function updateCartItemPriceView(elmPrice, price, orderCount) { elmPrice.textContent = (orderCount >= 2) ? `${ price } x ${ orderCount }` : price; } function updateAddButtonItemCount(elmButton, orderCount) { const { text: buttonText } = elmButton.dataset; elmButton.textContent = (orderCount >= 1) ? `${ buttonText } (${ orderCount })` : buttonText; } function updateOrderCounts(pid, context) { const { target: { elmMainOverview, elmCartOverview, elmCartTotal }, state: shoppingState, } = context; const shoppingItem = shoppingState[pid]; const orderCount = shoppingItem?.checkout?.orderCount ?? 0; const elmButton = elmMainOverview .querySelector(`[data-add-pid="${ pid }"]`); const elmPrice = (orderCount >= 1) && elmCartOverview .querySelector(`[data-pid="${ pid }"] dd`); if (elmButton) { updateAddButtonItemCount(elmButton, orderCount); } if (elmPrice) { updateCartItemPriceView(elmPrice, shoppingItem?.data?.price, orderCount); } updateShoppingCartTotal(elmCartTotal, shoppingState); } function handleAddToCartWithBoundTargetAndState(evt) { const target = evt.target.closest('[data-add-pid]'); if (target) { const { addPid: pid } = target.dataset; const { target: { elmCartOverview }, state: shoppingState, } = this; const item = shoppingState[pid]; if (item) { if (item.checkout.isInCart === false) { elmCartOverview.appendChild(item.view.cart.cloneNode(true)); item.checkout.isInCart = true; } item.checkout.orderCount += 1; scrollIntoViewIfNeeded( elmCartOverview.querySelector(`[data-pid="${ pid }"]`) ); updateOrderCounts(pid, this); } // console.log('Add To Cart :: pid ...', pid); } console.log('Add To Cart :: evt.target ...', evt.target); } function handleRemoveFromCartWithBoundTargetAndState(evt) { const target = evt.target.closest('[data-remove-pid]'); if (target) { const { removePid: pid } = target.dataset; const { target: { elmMainOverview, elmCartOverview }, state: shoppingState, } = this; const item = shoppingState[pid]; if (item) { const selector = `[data-pid="${ pid }"]`; scrollIntoViewIfNeeded(elmMainOverview.querySelector(selector)); elmCartOverview.querySelector(selector)?.remove(); elmMainOverview .querySelector(`[data-add-pid="${ pid }"]`).focus?.(); item.checkout.isInCart = false; item.checkout.orderCount = 0; updateOrderCounts(pid, this); } // console.log('Remove From Cart :: pid ...', pid); } console.log('Remove From Cart :: evt.target ...', evt.target); } function main() { const shoppingState = productList .map(createShoppingItem) .reduce((state, item) => Object.assign(state, { [item.data.pid]: item }), Object.create(null) ); console.log({ shoppingState }) const elmMainOverview = document .querySelector('[data-product-overview]'); const elmShoppingCart = document .querySelector('[data-shopping-cart]'); const elmCartOverview = elmShoppingCart ?.querySelector('[data-cart-overview]'); const elmCartTotal = elmShoppingCart ?.querySelector('[data-cart-total]'); const handlerContext = { target: { elmMainOverview, elmCartOverview, elmCartTotal, }, state: shoppingState, }; elmMainOverview.addEventListener('click', handleAddToCartWithBoundTargetAndState.bind(handlerContext) ); elmCartOverview.addEventListener('click', handleRemoveFromCartWithBoundTargetAndState.bind(handlerContext) ); // initially render product list from shopping state. Object .values(shoppingState) .forEach(item => elmMainOverview.appendChild(item.view.main.cloneNode(true)) ); } main();
 * { margin: 0; padding: 0; } ul, li { list-style: none; } li { position: relative; margin-bottom: 5px; padding: 5px; } li:hover { background-color: #eee; } h3, dl, button { font-size: 12px; } img { max-height: 54px; max-width: 72px; } dl::after { clear: left; } dl dt { float: left; } dl dd::before { content: ': '; } button { position: absolute; right: 5px; bottom: 5px; } button:hover { cursor: pointer; } button:target, button:focus, button:focus-within { outline: 1px solid #06f; } main { position: relative; max-width: 25%; } #mini-cart { position: fixed; right: 60%; top: 0; min-width: 14%; height: 100%; overflow-y: scroll; font-size: 12px; } #mini-cart button { position: unset; } .as-console-wrapper { min-height: 100%!important; width: 60%; top: 0; left: auto!important; right: 0; }
 <main> <ul data-product-overview> </ul> </main> <section id="mini-cart" data-shopping-cart> <a href="#mini-cart"> Mini Cart <output data-cart-total></output> </a> <ul data-cart-overview> </ul> </section>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM