JS预算计算器删除功能故障:无法更新newMoneyArr与可用余额
修复预算计算器的transactionDelete函数
我正在开发一款JS预算计算器应用,已完成部分功能,但卡在transactionDelete函数上。该函数需要实现从收入/支出区域删除交易记录,同时更新moneyArr并在可用余额中显示最新数值。
原代码
JavaScript
const incomeSection = document.querySelector(".income-area"); const expensesSection = document.querySelector(".expenses-area"); const availableMoney = document.querySelector(".available-money"); const addTransactionPanel = document.querySelector(".add-transaction-panel"); const nameInput = document.querySelector("#name"); const amountInput = document.querySelector("#amount"); const categorySelect = document.querySelector("#category"); const errorTransactionname = document.querySelector(".error-transaction-name"); const errorTransactionAmount = document.querySelector( ".error-transaction-amount" ); const errorTransactionOption = document.querySelector( ".error-transaction-option" ); const errorMsg = document.querySelector(".error-msg"); const addTransactionBtn = document.querySelector(".add-transaction"); const saveBtn = document.querySelector(".save"); const cancelBtn = document.querySelector(".cancel"); const deleteAllBtn = document.querySelector(".delete-all"); let ID = 0; let newMoneyArr let moneyArr = [] const checkTransactionName = () => { if (nameInput.value.length == 0) { errorTransactionname.style.display = "block"; errorTransactionname.innerHTML = "Transaction name cannot be empty!"; } else if (nameInput.value.length > 10) { errorTransactionname.style.display = "block"; errorTransactionname.innerHTML = "Transaction name cannot be longer then 10 charcters"; } else { errorTransactionname.innerHTML = ""; } }; const checkTransactionAmount = () => { if (amountInput.value.length == 0) { errorTransactionAmount.style.display = "block"; errorTransactionAmount.innerHTML = "Transaction amount cannot be empty!"; } else if (amountInput.value.length >= 6) { errorTransactionAmount.style.display = "block"; errorTransactionAmount.innerHTML = "Transaction amount cannot be longer then 5 digits"; } else { errorTransactionAmount.innerHTML = ""; } }; const checkSelect = () => { if (categorySelect.selectedIndex == 0) { errorTransactionOption.style.display = "block"; errorTransactionOption.innerHTML = "Choose one of the two options"; } else { errorTransactionOption.innerHTML = ""; } }; const createTransaction = () => { checkTransactionName(); checkTransactionAmount(); checkSelect(); if ( errorTransactionAmount.innerHTML != "" || errorTransactionAmount.innerHTML != "" || errorTransactionOption.innerHTML != "" ) { errorMsg.style.display = "block"; errorMsg.innerHTML = "Fill out all the spaces correctly please"; } else { let newTransaction = document.createElement("li"); newTransaction.setAttribute("id", ID); newTransaction.classList.add("transaction"); newTransaction.innerHTML = `<p class="transaction-name">${nameInput.value}</p> <p class="transaction-amount">${amountInput.value}zł <button onclick = 'transactionDelete(${ID})' class="delete"> <i class="fas fa-times"></i></button></p>`; if (categorySelect.selectedIndex == 1) { incomeSection.appendChild(newTransaction); newTransaction.classList.add("income-transaction"); } else { expensesSection.appendChild(newTransaction); newTransaction.classList.add("expense-transaction"); } ID++; newBalance(); closePanel(); } }; const newBalance = () => { if (categorySelect.selectedIndex == 1) { moneyArr.push(parseFloat(amountInput.value)); } else { let newAmount2 = parseFloat(amountInput.value); let newAmount = -newAmount2; moneyArr.push(newAmount); } let newMoneyArr = moneyArr.reduce((a, b) => { return a + b; }); }; const clearInputs = () => { nameInput.value = ""; amountInput.value = ""; categorySelect.selectedIndex = 0; errorTransactionname.innerHTML = ""; errorTransactionAmount.innerHTML = ""; errorTransactionOption.innerHTML = ""; errorMsg.innerHTML = ""; }; saveBtn.addEventListener("click", createTransaction); addTransactionBtn.addEventListener( "click", (showPanel = () => { addTransactionPanel.style.display = "flex"; }) ); cancelBtn.addEventListener( "click", (closePanel = () => { addTransactionPanel.style.display = "none"; clearInputs(); }) ); const deleteAllTransactions = () => { incomeSection.innerHTML = "<h3>Income</h3>"; expensesSection.innerHTML = "<h3>Expenses</h3>"; availableMoney.textContent = "0$"; moneyArr = [0]; }; deleteAllBtn.addEventListener("click", deleteAllTransactions); // 待完善的函数 transactionDelete = (id) => { const transactionToDelete = document.getElementById(id); const transactionAmount = parseFloat(transactionToDelete.childNodes[2].innerText); if (transactionToDelete.classList.contains('income-transaction')) { incomeSection.removeChild(transactionToDelete); } else { expensesSection.removeChild(transactionToDelete); } };
HTML
<link href="https://fonts.googleapis.com/css?family=Montserrat:200,400,700&display=swap&subset=latin-ext" rel="stylesheet"> <link rel="stylesheet" href="style.css"> <script src="https://kit.fontawesome.com/6c5198f753.js" crossorigin="anonymous"></script> <header> <h1><i class="fas fa-wallet"></i> Wallet</h1> <p>Finance manager</p> </header> <main> <div class="transactions-wrapper"> <section class="transactions"> <h2 class="title">Transaction list</h2> <div class="transaction-list"> <div class="income-area"> <h3>Income</h3> </div> <div class="expenses-area"> <h3>Expenses</h3> </div> </div> </section> </div> <section class="options"> <div> <h2 class="title">Available money:</h2> <p class="available-money">0$</p> </div> <div class="controls"> <button class="add-transaction"><i class="fas fa-plus"></i> add transaction</button> <button class="delete-all"><i class="far fa-trash-alt"></i> delete everything</button> </div> </section> </main> <div class="add-transaction-panel"> <div class="panel-wrapper"> <h2 class="title">add new transaction</h2> <div class="form-box"> <label for="name">name:</label> <input type="text" id="name"> <p class="error-transaction-name"></p> </div> <div class="form-box"> <label for="amount">amount:</label> <input type="number" id="amount"> <p class="error-transaction-amount"></p> </div> <div class="form-box"> <label for="category">select category:</label> <select id="category"> <option value="none" selected>chose if the transaction is a income or expense</option> <option value="income">income</option> <option value="shopping">expense</option> </select> <p class="error-transaction-option"></p> </div> <p class="error-msg"></p> <div class="panel-buttons"> <button class="save" type="button"><i class="fas fa-save"></i> save</button> <button class="cancel" type="button"><i class="far fa-window-close"></i> cancel</button> </div> </div> </div>
解决方案
要完成删除功能,需解决三个核心问题:正确提取金额、同步更新数据数组、刷新页面余额显示,同时修复原代码的逻辑漏洞。
1. 重构newBalance函数,适配后续删除逻辑
将moneyArr改为存储带ID的对象,方便删除时精准匹配,同时补全页面余额更新逻辑:
const newBalance = () => { // 初始化空数组(避免全删后残留0值) if (moneyArr.length === 0 || moneyArr[0] === 0) { moneyArr = []; } // 存储带ID的交易数据 if (categorySelect.selectedIndex === 1) { moneyArr.push({ id: ID, amount: parseFloat(amountInput.value) }); } else { moneyArr.push({ id: ID, amount: -parseFloat(amountInput.value) }); } // 计算总余额并更新页面 const total = moneyArr.reduce((sum, item) => sum + item.amount, 0); availableMoney.textContent = `${total.toFixed(2)}zł`; };
2. 完善transactionDelete函数
处理金额提取、DOM移除、数组更新和余额刷新:
transactionDelete = (id) => { const transactionToDelete = document.getElementById(id); // 提取金额:移除zł符号后转数字 const amountText = transactionToDelete.querySelector('.transaction-amount').textContent; const transactionAmount = parseFloat(amountText.replace('zł', '').trim()); // 从DOM中移除交易项 if (transactionToDelete.classList.contains('income-transaction')) { incomeSection.removeChild(transactionToDelete); } else { expensesSection.removeChild(transactionToDelete); } // 从数据数组中移除对应项 moneyArr = moneyArr.filter(item => item.id !== id); // 重新计算并更新余额 const total = moneyArr.reduce((sum, item) => sum + item.amount, 0); availableMoney.textContent = `${total.toFixed(2)}zł`; };
3. 同步修复deleteAllTransactions函数
适配新的数据结构,确保全删后数据和页面一致:
const deleteAllTransactions = () => { incomeSection.innerHTML = "<h3>Income</h3>"; expensesSection.innerHTML = "<h3>Expenses</h3>"; availableMoney.textContent = "0zł"; moneyArr = []; };
内容的提问来源于stack exchange,提问作者Marcelo
相关产品推荐
相关产品推荐

