JavaScript 增加按钮只增加一次



我是JS的初学者,在购物车工作。我有几个产品使用 ES6 模板字符串在页面中呈现。到目前为止一切正常,您可以将物品添加到购物篮和购物篮中,并正确更新总值。我遇到的唯一麻烦是增加/减少按钮:它们只工作一次,如果您再次单击控制台中打印的数量保持不变。

我确实找到了与递增/递减功能相关的其他 SO 帖子,但该按钮只工作一次,所以我认为问题与我忽略的代码中的其他内容有关。

请参阅下面的代码:

这是将呈现的购物车

// select ul
const shoppingCart = document.querySelector('.cart-items');
// create a li item inside ul
let billContainer = document.createElement('li');
// attach an event listener to every  li
billContainer.classList.add('list');
// create the markup for every item added to the cart
for(let j = 0; j < basket.length; j++){
    const billMarkup =  `
                <p class="prodName">${basket[j].name}</p>
                <div class="button-wrapper">
                    <button type="button" name="increase" class="increase">+</button>
                    <span class="quantity">${basket[j].quantity}</span>
                    <button type="button" name="decrease" class="decrease">-</button>
                </div>
                <p class="totPrice">£${basket[j].price}</p>
        `;
    // add the markup to the DOM
    billContainer.innerHTML = billMarkup;
    shoppingCart.appendChild(billContainer);
}

这是增加/减少功能(按钮的事件侦听器附加到它们的父"li"(:

// attach an event listener to every li
const li = document.querySelectorAll('.list');
li.forEach( liItem => liItem.addEventListener('click', updateBill));
// add or remove items on click
function updateBill(e){
    if(e.target.nodeName === 'BUTTON'){
    // current value in the basket
    let value = parseInt(this.querySelector('.quantity').textContent);
    // if the user clicks on 'increase' button
    if(e.target.name === 'increase'){
        value++;
        console.log(value);
    // if the user clicks on 'decrease' button
    } else if(e.target.name === 'decrease'){
         value < 1 ? value = 1 : '';
         value--;
         console.log(value);
        }
    }
}

谢谢!

问题

加/减按钮,包括/减去一次,然后不会再进一步了。

解释

一旦值更改,它只是浮动在控制台中的变量中的一个数字,因为这是与该值相关的最后一条语句。因此,只有初始更改是成功的,但是当第二次单击按钮时,该函数将返回到span.quantity并获取从上次单击以来从未更新的值。

溶液

解决手头问题的最简单方法是更新 span.quantity 的值:

if (e.target.name === 'increase') {
    value++;
    console.log(value);
} else if (e.target.name === 'decrease') {
    value--;
    value = value < 1 ? 1 : value;
    console.log(value);
} else {
    return false;
}
this.querySelector('.quantity').textContent = value;

因为您没有提供功能演示或可复制的演示,所以我没有费心去测试它,也没有尝试抽查您的代码。重写源代码和解决问题并可能防止将来出现问题的工作量更少。


演示亮点

该演示使用不同的 API 来引用窗体控件和备用方法和属性,这些方法和属性是更常用方法和属性的更好版本。使用事件委派。数组方法可能有点矫枉过正,但我喜欢使用它们。以下是对演示的行项目引用,不幸的是堆栈代码段没有行号。Plunker - 索引.html和 README.md 可以与行号一起读取。

HTMLFormControlsCollection


  • 52 宣布<form>

  • 53 引用所有表单控件,

  • 92-95 创建对每个窗体控件的非常短的引用,

  • 96-99 创建对其值的引用并将其转换为数字,

  • 102-103, 109-110 简单和简短的表达式,

  • 122 总价值

模板文字


  • 75-83 通过使用语义元素改进了列表项的布局。每个元素都分配有唯一的 #id,

  • 92-94 根据89和90的结果灵活引用 #ids。

数组方法


  • 90-91 通过规划特定的命名策略:abc-0split('-').pop()返回 id 的数字结尾,split('-').shift()返回短划线前的字母,

  • 113-120 收集所有.prc; map() 返回一个价格总计数组; reduce()返回总和;

事件委派/事件对象


  • 52 参考<form>

  • 54 注册点击事件<form>。这是唯一需要的事件侦听器,它将适用于它的所有子代/后代,

  • 88-91, 100 使用 Event.target 属性引用事件的来源,不仅确定单击的元素,还确定其他人,如兄弟姐妹、父母/祖先和子/后代。

杂项


  • 56-71 看起来basket是一个对象数组?在OP中没有看到它,所以我不得不猜测。删除了 basket[j].quantity 属性,因为每个项目最初的数量为 1 更有意义。

  • 84 insertAdjacentHTML() innerHTML类固醇。


普伦克

演示

<!DOCTYPE html>
<html>
<head>
  <style>
    html,
    body {
      font: 400 16px/1.1 Consolas;
    }
    
    legend {
      font-size: 1.3rem;
    }
    
    output,
    input {
      display: inline-block;
      text-align: center;
    }
    
    [id^=qty] {
      width: 1.5ch;
    }
    
    [id^=prc] {
      min-width: 9ch;
    }
    
    [id^=prc]::before {
      content: "= £";
    }
    
    [id^=bas]::before {
      content: " x  £";
    }
    
    #cart+label {
      display: inline-block;
      margin: 10px 0 0 40%;
    }
    
    #total::before {
      content: " £";
    }
  </style>
</head>
<body>
  <form id='cart'></form>
  <label>Total:
    <output id='total' form='cart'>0.00</output>
  </label>
  <script>
    var cart = document.forms.cart;
    var x = cart.elements;
    cart.addEventListener('click', updateBill, false);
    var basket = [{
      name: "thing0",
      price: 1.99
    }, {
      name: "thing1",
      price: 12.99
    }, {
      name: "thing2",
      price: 21.59
    }, {
      name: "thing3",
      price: 0.09
    }, {
      name: "thing4",
      price: 5.99
    }];
    for (let j = 0; j < basket.length; j++) {
      var details = `
      <fieldset id="item-${j}">
        <legend>${basket[j].name}</legend>
        <button id="inc-${j}" type="button">+</button>
        <output id="qty-${j}">1</output>
        <button id="dec-${j}" type="button">-</button>
        <output id="bas-${j}">${basket[j].price}</output>
        <output id="prc-${j}" class="prc">${basket[j].price}</output>
    </fieldset>
    `;
      cart.insertAdjacentHTML('beforeend', details);
    }
    function updateBill(e) {
      if (e.target.type === 'button') {
        var ID = e.target.parentElement.id;
        var idx = ID.split('-').pop();
        var dir = e.target.id.split('-').shift();
        var qty = x.namedItem(`qty-${idx}`);
        var bas = x.namedItem(`bas-${idx}`);
        var prc = x.namedItem(`prc-${idx}`);
        var sum = x.total;
        var quantity = parseInt(qty.value, 10);
        var base = parseFloat(bas.value).toFixed(2);
        var price = parseFloat(prc.value).toFixed(2);
        var total = parseFloat(sum.value).toFixed(2);
        if (dir === "inc") {
          quantity++;
          qty.value = quantity;
          prc.value = quantity * base;
        } else {
          quantity--;
          if (quantity <= 0) {
            quantity = 1;
          }
          qty.value = quantity;
          prc.value = quantity * base;
        }
      }
      var prices = Array.from(document.querySelectorAll('.prc'));
      var numbers = prices.map(function(dig, idx) {
        return parseFloat(dig.value);
      });
      var grandTotal = numbers.reduce(function(acc, cur) {
        return acc + cur;
      }, 0);
      x.total.value = grandTotal.toFixed(2);
    }
  </script>
</body>
</html>

最新更新