购物list/how 再次添加删除item/javascript
Shopping list/how to add again removed item/javascript
这是我的 fiddle 购物清单。
https://fiddle.jshell.net/k9L4gamm/
快完成了,我最不想做的事情是在删除项目后再次添加(这是注释的代码)。当我更改其 class,但 "else" 不想再次添加价格时,我的工作是从要支付的金额中减去项目价格。我是编码的新手,我现在正在参加编码训练营,但我找不到任何 if/else 语句无法正常工作的原因。我将非常感谢所有建议。
首先,我可以说(正如 @trincot 评论的那样)- 你真的需要验证这个服务器端!
其次,您的代码很糟糕,缩进严重并且没有进行输入检查! (例如,我可以输入 "foo" 作为价格)。
也就是说,您的问题归结为 2 行代码:
- 您的循环条件没有考虑到您有 2 extra table 行...
for (var z=0;z<myRow.length;z++) {
应该变成:
for (var z=1;z<myRow.length-1;z++) {
(注意 0
变成了 1
而 length
变成了 -1
)。
- 您使用 DOM 访问 节点 而不是 元素 !
for 循环之后的下一行:
var subRow = myRow[z].lastChild;
需要:
var subRow = myRow[z].children[myRow[z].children.length-1];
这是因为(在大多数浏览器中),lastChild
将是 text 节点,而不是最后一个 element。
代码的主要问题在这一行:
var subRow = myRow[z].lastChild;
这为某些行提供了文本节点对象,而不是 TD
元素。并且文本节点没有 innerHTML
属性。由于您的其余代码都适用于此,因此您在计算中得到 undefined
,但事情出错了。
但是,由于您已经有了在 addProduct 函数中计算总和的代码,很遗憾在 removeBtn[= 中几乎复制了该代码50=] 事件处理程序。
所以,我建议创建一个单独的函数,它将计算总数并显示出来。它将充分利用您拥有的两个代码片段,避免上述问题:
function displayTotal() {
// Code taken from the last part of addProduct:
var toPay = document.getElementsByClassName("altogether");
var suma = 0;
for (var n=0; n<toPay.length;n++) {
// This condition is inspired by the removeBtn click handler:
if (!toPay[n].parentElement.classList.contains("strike")) {
suma = suma + parseFloat(toPay[n].innerHTML);
}
}
// Only put the total at the end, not in the loop:
howMuch.innerHTML = parseFloat(suma);
}
虽然与您提到的问题无关,但我也建议在您开始修改 table 之前进行任何验证检查。检查空输入也是不够的。您还应该检查输入是否为数字。
考虑到这一点,您的 addProduct 函数可能如下所示:
function addProduct() {
// Before doing anything test the input is complete:
if (quantityInput.value == "" || isNaN(quantityInput.value)) {
alert("Please add quantity");
return; // and exit!
}
if (priceInput.value == "" || isNaN(priceInput.value)) {
alert("Please add price");
return; // and exit!
}
var removeBtn = document.createElement("button");
removeBtn.innerHTML="Skreśl przedmiot";
var row = table.insertRow(1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
var cell4 = row.insertCell(3);
var cell5 = row.insertCell(4);
cell5.classList.add("altogether");
cell1.appendChild(removeBtn);
cell2.innerHTML = productInput.value
cell3.innerHTML = parseFloat(quantityInput.value);
cell4.innerHTML = parseFloat(priceInput.value);
cell5.innerHTML = parseFloat(quantity.value)*parseFloat(price.value);
removeBtn.addEventListener("click", function(event){
this.parentElement.parentElement.classList.toggle("strike");
displayTotal();
});
// Code moved to function
displayTotal();
}
因此您注意到 displayTotal 在两个地方被调用:添加产品之后和切换删除之后。这样你就避免了代码重复。
这是更新后的 fiddle。
还有什么可以改进的地方
最好将购物车内容保存在一个变量中(一个包含具有商品、价格和数量属性的对象的数组)。这样你就不必读取 HTML 元素来找回这些数据,这不是很有效。
其次,您最好将值分配给 textContent
而不是 innerHTML
。这样你就可以避免特殊字符的问题。例如,如果您的产品名称中有一个 <
字符,您会看到其中的一部分没有显示。 textContent
.
不会有这个
最后,如果在实际应用中使用,购物车必须由服务器管理。这是因为一个网页,以及上面的数字很容易被客户端软件、浏览器插件等修改,所以它们是不可信任的。所有检查都必须由服务器应用程序再次完成,该应用程序还应该有一个包含正确产品价格的数据库等。
试试这个解决方案 https://fiddle.jshell.net/uja994ae/。
当您删除一个项目时,您需要再次输入 0
总数。然后只增加需要计数的项目。实际上,这不是一个好的解决方案,只有我在您的代码中调整了解决方案。为了更好地工作,您需要将 total
(代码中的 howMuch.innerHTML
)放在一个全局变量中,并且只增加或减少 added/removed 新项目。但是好吧,要做到这一点,您需要再次执行所有代码...
removeBtn.addEventListener("click", function(event){
var rowToDelete = this.parentElement.parentElement;
var myRow = document.getElementsByTagName("tr");
rowToDelete.classList.toggle("strike");
howMuch.innerHTML = "0";
for (var z=0;z<myRow.length;z++) {
var subRowValue = myRow[z].lastChild.innerHTML;
if (subRowValue && !myRow[z].classList.contains("strike")) {
howMuch.innerHTML = parseFloat(howMuch.innerHTML)+parseFloat(subRowValue);
}
}
});
这是我的 fiddle 购物清单。 https://fiddle.jshell.net/k9L4gamm/ 快完成了,我最不想做的事情是在删除项目后再次添加(这是注释的代码)。当我更改其 class,但 "else" 不想再次添加价格时,我的工作是从要支付的金额中减去项目价格。我是编码的新手,我现在正在参加编码训练营,但我找不到任何 if/else 语句无法正常工作的原因。我将非常感谢所有建议。
首先,我可以说(正如 @trincot 评论的那样)- 你真的需要验证这个服务器端!
其次,您的代码很糟糕,缩进严重并且没有进行输入检查! (例如,我可以输入 "foo" 作为价格)。
也就是说,您的问题归结为 2 行代码:
- 您的循环条件没有考虑到您有 2 extra table 行...
for (var z=0;z<myRow.length;z++) {
应该变成:
for (var z=1;z<myRow.length-1;z++) {
(注意 0
变成了 1
而 length
变成了 -1
)。
- 您使用 DOM 访问 节点 而不是 元素 !
for 循环之后的下一行:
var subRow = myRow[z].lastChild;
需要:
var subRow = myRow[z].children[myRow[z].children.length-1];
这是因为(在大多数浏览器中),lastChild
将是 text 节点,而不是最后一个 element。
代码的主要问题在这一行:
var subRow = myRow[z].lastChild;
这为某些行提供了文本节点对象,而不是 TD
元素。并且文本节点没有 innerHTML
属性。由于您的其余代码都适用于此,因此您在计算中得到 undefined
,但事情出错了。
但是,由于您已经有了在 addProduct 函数中计算总和的代码,很遗憾在 removeBtn[= 中几乎复制了该代码50=] 事件处理程序。
所以,我建议创建一个单独的函数,它将计算总数并显示出来。它将充分利用您拥有的两个代码片段,避免上述问题:
function displayTotal() {
// Code taken from the last part of addProduct:
var toPay = document.getElementsByClassName("altogether");
var suma = 0;
for (var n=0; n<toPay.length;n++) {
// This condition is inspired by the removeBtn click handler:
if (!toPay[n].parentElement.classList.contains("strike")) {
suma = suma + parseFloat(toPay[n].innerHTML);
}
}
// Only put the total at the end, not in the loop:
howMuch.innerHTML = parseFloat(suma);
}
虽然与您提到的问题无关,但我也建议在您开始修改 table 之前进行任何验证检查。检查空输入也是不够的。您还应该检查输入是否为数字。
考虑到这一点,您的 addProduct 函数可能如下所示:
function addProduct() {
// Before doing anything test the input is complete:
if (quantityInput.value == "" || isNaN(quantityInput.value)) {
alert("Please add quantity");
return; // and exit!
}
if (priceInput.value == "" || isNaN(priceInput.value)) {
alert("Please add price");
return; // and exit!
}
var removeBtn = document.createElement("button");
removeBtn.innerHTML="Skreśl przedmiot";
var row = table.insertRow(1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
var cell3 = row.insertCell(2);
var cell4 = row.insertCell(3);
var cell5 = row.insertCell(4);
cell5.classList.add("altogether");
cell1.appendChild(removeBtn);
cell2.innerHTML = productInput.value
cell3.innerHTML = parseFloat(quantityInput.value);
cell4.innerHTML = parseFloat(priceInput.value);
cell5.innerHTML = parseFloat(quantity.value)*parseFloat(price.value);
removeBtn.addEventListener("click", function(event){
this.parentElement.parentElement.classList.toggle("strike");
displayTotal();
});
// Code moved to function
displayTotal();
}
因此您注意到 displayTotal 在两个地方被调用:添加产品之后和切换删除之后。这样你就避免了代码重复。
这是更新后的 fiddle。
还有什么可以改进的地方
最好将购物车内容保存在一个变量中(一个包含具有商品、价格和数量属性的对象的数组)。这样你就不必读取 HTML 元素来找回这些数据,这不是很有效。
其次,您最好将值分配给 textContent
而不是 innerHTML
。这样你就可以避免特殊字符的问题。例如,如果您的产品名称中有一个 <
字符,您会看到其中的一部分没有显示。 textContent
.
最后,如果在实际应用中使用,购物车必须由服务器管理。这是因为一个网页,以及上面的数字很容易被客户端软件、浏览器插件等修改,所以它们是不可信任的。所有检查都必须由服务器应用程序再次完成,该应用程序还应该有一个包含正确产品价格的数据库等。
试试这个解决方案 https://fiddle.jshell.net/uja994ae/。
当您删除一个项目时,您需要再次输入 0
总数。然后只增加需要计数的项目。实际上,这不是一个好的解决方案,只有我在您的代码中调整了解决方案。为了更好地工作,您需要将 total
(代码中的 howMuch.innerHTML
)放在一个全局变量中,并且只增加或减少 added/removed 新项目。但是好吧,要做到这一点,您需要再次执行所有代码...
removeBtn.addEventListener("click", function(event){
var rowToDelete = this.parentElement.parentElement;
var myRow = document.getElementsByTagName("tr");
rowToDelete.classList.toggle("strike");
howMuch.innerHTML = "0";
for (var z=0;z<myRow.length;z++) {
var subRowValue = myRow[z].lastChild.innerHTML;
if (subRowValue && !myRow[z].classList.contains("strike")) {
howMuch.innerHTML = parseFloat(howMuch.innerHTML)+parseFloat(subRowValue);
}
}
});