页面重载后购物车onclick删除按钮行为异常问题排查
购物车页面重载后删除按钮功能异常问题
我开发了一款购物车功能,支持添加商品、增减数量,点击删除按钮可移除商品。通过localStorage存储数据,实现页面重载后重新渲染购物车。目前重载后购物车渲染正常,但点击删除按钮会删除错误的商品,再次删除时会导致代码崩溃。该功能使用与未重载时相同的逻辑,无法定位问题。
各函数作用说明
additem():手动渲染购物车商品window.onload():通过存储的数据重复additem()流程,重新渲染购物车updateprice():更新购物车总价updatestorage():更新localStorage中的商品字符串数据
原始代码
function updatestorage(name,cost,code,operator){ if (operator === 'add'){ if(localStorage.getItem("stringitem") === null || localStorage.getItem("stringitem") === ''){ //sets the first item in the string of items to localstorage let stringofitems = '1,' + name + ',' + cost + ',' + code + ',1'; localStorage.setItem("stringitem",stringofitems); }else{ let stringofitems = localStorage.getItem("stringitem"); let arr = stringofitems.split(","); let count = (arr.length / 5 ); let updated = 0; for(x = 1; x < arr.length; x = x + 5){ if (arr[x] === name){ arr[x-1] = parseInt(arr[x-1]) + parseInt(1); updated = 1; let newstring = arr.join(); localStorage.setItem("stringitem",newstring); } } if(updated == 0){ count = parseInt(count) + parseInt(1); let newstringofitems = stringofitems + ',1,' + name + ',' + cost + ',' + code + ',' + count; localStorage.setItem("stringitem",newstringofitems); } } } if (operator === 'sub'){ let stringofitems = localStorage.getItem("stringitem"); let arr = stringofitems.split(","); let count = (arr.length / 5 ); console.log('count = ' + count); console.log('arr = ' + arr.length); for(x = 1; x < arr.length; x = x + 5){ if (arr[x] === name){ arr.splice(x-1,5); let newstring = arr.join(); localStorage.setItem("stringitem",newstring); } } } } function updateprice(x,operation,name){ //updates the total price and stores in localstorage(long memory) x = x.replace('$',''); if(operation === 'add'){ if(localStorage.getItem("currentprice") === null){ localStorage.setItem("currentprice",x); document.getElementById('newprice').innerHTML = '$' + x; }else{ let temp = localStorage.getItem("currentprice"); temp = parseFloat(temp) + parseFloat(x); temp = temp.toFixed(2); localStorage.setItem("currentprice",temp); document.getElementById('newprice').innerHTML = '$' + temp; } } if(operation === 'sub'){ if(localStorage.getItem("currentprice") === null){ localStorage.setItem("currentprice",0.00); document.getElementById('newprice').innerHTML = '$0.00'; }else{ let temp = localStorage.getItem("currentprice"); // get the total of the cart let stringofitems = localStorage.getItem("stringitem"); //locate the item to remove and how many qty are in cart. let arr = stringofitems.split(","); //define array let count = (arr.length / 5 ); let qty; let amount; for(x = 1; x < arr.length; x = x + 5){ if (arr[x] === name){ qty = arr[x-1]; amount = arr[x+1] } } amount = amount.replace('$',''); temp = parseFloat(temp) - (parseFloat(amount) * parseInt(qty)); //not yet temp = temp.toFixed(2); temp = temp.replace('-',''); if( temp <= 0 ){ localStorage.setItem("currentprice",0.00); }else{ localStorage.setItem("currentprice",temp); } document.getElementById('newprice').innerHTML = '$' + temp; } } } function additem(name, cost, code){ //adds the product to the receipt frame //delete if it exist------- name = name.replace(/\s+/g, "-"); const myDiv = document.querySelector('.basketshow'); const myName = myDiv.querySelector('#a' + name); const myValue = myDiv.querySelector('#a' + name + 1); let qty; let code1; if(myValue !== null){ const codeinner = myValue.innerHTML; qty = parseInt(codeinner) + parseInt(1); code1 = 'a' + qty + ',' + code; }else{ qty = 1; code1 = 'a' + qty + ',' + code; } if (myName !== null){ myName.parentElement.remove(); } //------------------------- var new_tr = document.createElement("tr"); //new table row new_tr.classList.add('regrow'); var new_td0 = document.createElement('td'); //td with id to hold qty new_td0.classList.add('regbody'); new_td0.classList.add('recqtydiv'); new_td0.setAttribute('id', 'a' + name + 1); var new_td1 = document.createElement('td'); //td with id to hold name new_td1.classList.add('regbody'); new_td1.classList.add('recnamediv'); new_td1.setAttribute('id', 'a' + name); var new_td2 = document.createElement('td'); //td to hold cost new_td2.classList.add('regbody'); new_td2.classList.add('regr'); new_td2.classList.add('reccostdiv'); var new_td3 = document.createElement('td'); //td to hold delete button new_td3.classList.add('regbody'); var new_p = document.createElement('p'); //p to be the delete button new_p.classList.add('regdel'); var new_input = document.createElement('input'); //hidden input to hold the information for the form submission new_input.setAttribute("type", "hidden"); new_input.setAttribute("name",code); new_input.setAttribute("value",code1); new_td0.innerHTML = qty; new_td1.innerHTML = name; new_td2.innerHTML = cost; new_p.innerHTML = 'Del'; new_td3.onclick = function() { updateprice(cost,'sub',name); updatestorage(name,cost,code,'sub'); this.parentElement.remove(this); } new_td3.appendChild(new_p); new_tr.appendChild(new_td0); new_tr.appendChild(new_td1); new_tr.appendChild(new_input); new_tr.appendChild(new_td2); new_tr.appendChild(new_td3); $("#recbody").prepend($(new_tr).fadeIn('slow')); updateprice(cost,'add',name); updatestorage(name,cost,code,'add'); } window.onload = function() { let stringofitems = localStorage.getItem("stringitem"); let price = localStorage.getItem("currentprice"); if(stringofitems !== null){ if(price === '0' || price === ''){ document.getElementById('newprice').innerHTML = '$0.00'; }else{ let arr = stringofitems.split(","); //define array let count = (arr.length / 5 ); let qty; for(x = 1; x < arr.length; x = x + 5){ qty = arr[x-1]; names = arr[x]; cost = arr[x+1]; code = arr[x+2]; code1 = 'a' + qty + ',' + code; const myDiv = document.querySelector('.basketshow'); var new_tr = document.createElement("tr"); //new table row new_tr.classList.add('regrow'); var new_td0 = document.createElement('td'); //td with id to hold qty new_td0.classList.add('regbody'); new_td0.classList.add('recqtydiv'); new_td0.setAttribute('id', 'a' + names + 1); var new_td1 = document.createElement('td'); //td with id to hold name new_td1.classList.add('regbody'); new_td1.classList.add('recnamediv'); new_td1.setAttribute('id', 'a' + names); var new_td2 = document.createElement('td'); //td to hold cost new_td2.classList.add('regbody'); new_td2.classList.add('regr'); new_td2.classList.add('reccostdiv'); var new_td3 = document.createElement('td'); //td to hold delete button new_td3.classList.add('regbody'); var new_p = document.createElement('p'); //p to be the delete button new_p.classList.add('regdel'); var new_input = document.createElement('input'); //hidden input to hold the information for the form submission new_input.setAttribute("type", "hidden"); new_input.setAttribute("name",code); new_input.setAttribute("value",code1); new_td0.innerHTML = qty; new_td1.innerHTML = names; new_td2.innerHTML = cost; new_p.innerHTML = 'Del'; new_td3.onclick = function() { updateprice(cost,'sub',names); updatestorage(names,cost,code,'sub'); this.parentElement.remove(this); } new_td3.appendChild(new_p); new_tr.appendChild(new_td0); new_tr.appendChild(new_td1); new_tr.appendChild(new_input); new_tr.appendChild(new_td2); new_tr.appendChild(new_td3); //document.getElementById("recbody").appendChild(new_tr); $("#recbody").prepend($(new_tr).fadeIn('slow')); //updateprice(cost,'add',code); //updatestorage(name,cost,code,'add'); } document.getElementById('newprice').innerHTML = '$' + price; } } };
问题根源与修复方案
核心问题1:全局变量污染循环索引
所有循环中的x未用let/var声明,导致成为全局变量。页面重载渲染时的循环会修改全局x的值,后续删除操作触发的循环会直接使用这个被污染的索引,从而定位到错误的商品项。
修复:所有循环中声明let x,示例:
// updatestorage中的add循环 for(let x = 1; x < arr.length; x = x + 5){...}
核心问题2:DOM元素删除逻辑错误
删除按钮的点击事件中,this.parentElement.remove(this)逻辑错误:new_td3是<td>元素,它的父元素是<tr>,这段代码只会删除当前<td>而非整个商品行,导致DOM结构混乱,后续操作崩溃。
修复:替换为移除整个商品行:
new_td3.onclick = function() { updateprice(cost,'sub',name); updatestorage(name,cost,code,'sub'); this.closest('tr').remove(); // 移除当前按钮所在的整行 }
核心问题3:删除存储项时未终止循环
updatestorage的sub操作中,找到匹配商品后未终止循环,且修改数组后继续遍历会导致索引错位,可能删除多个商品或触发数组越界错误。
修复:找到匹配项执行删除后,立即break终止循环:
if (operator === 'sub'){ let stringofitems = localStorage.getItem("stringitem"); if(!stringofitems) return; // 增加空值判断 let arr = stringofitems.split(","); for(let x = 1; x < arr.length; x = x + 5){ if (arr[x] === name){ arr.splice(x-1,5); let newstring = arr.join(); localStorage.setItem("stringitem",newstring); break; // 删除后终止循环 } } }
其他细节修复
updateprice函数中的循环变量x同样需要声明为let xwindow.onload中的循环变量x声明为let x- 增加空值判断,避免localStorage为空时触发错误
修复后的完整代码
function updatestorage(name,cost,code,operator){ if (operator === 'add'){ if(localStorage.getItem("stringitem") === null || localStorage.getItem("stringitem") === ''){ let stringofitems = '1,' + name + ',' + cost + ',' + code + ',1'; localStorage.setItem("stringitem",stringofitems); }else{ let stringofitems = localStorage.getItem("stringitem"); let arr = stringofitems.split(","); let count = (arr.length / 5 ); let updated = 0; for(let x = 1; x < arr.length; x = x + 5){ if (arr[x] === name){ arr[x-1] = parseInt(arr[x-1]) + 1; updated = 1; let newstring = arr.join(); localStorage.setItem("stringitem",newstring); break; // 找到后终止循环,避免重复更新 } } if(updated == 0){ count = parseInt(count) + 1; let newstringofitems = stringofitems + ',1,' + name + ',' + cost + ',' + code + ',' + count; localStorage.setItem("stringitem",newstringofitems); } } } if (operator === 'sub'){ let stringofitems = localStorage.getItem("stringitem"); if(!stringofitems) return; let arr = stringofitems.split(","); for(let x = 1; x < arr.length; x = x + 5){ if (arr[x] === name){ arr.splice(x-1,5); let newstring = arr.join(); localStorage.setItem("stringitem",newstring); break; } } } } function updateprice(x,operation,name){ x = x.replace('$',''); if(operation === 'add'){ if(localStorage.getItem("currentprice") === null){ localStorage.setItem("currentprice",x); document.getElementById('newprice').innerHTML = '$' + x; }else{ let temp = localStorage.getItem("currentprice"); temp = parseFloat(temp) + parseFloat(x); temp = temp.toFixed(2); localStorage.setItem("currentprice",temp); document.getElementById('newprice').innerHTML = '$' + temp; } } if(operation === 'sub'){ if(localStorage.getItem("currentprice") === null){ localStorage.setItem("currentprice",0.00); document.getElementById('newprice').innerHTML = '$0.00'; }else{ let temp = localStorage.getItem("currentprice"); let stringofitems = localStorage.getItem("stringitem"); if(!stringofitems){ localStorage.setItem("currentprice",0.00); document.getElementById('newprice').innerHTML = '$0.00'; return; } let arr = stringofitems.split(","); let qty; let amount; for(let x = 1; x < arr.length; x = x + 5){ if (arr[x] === name){ qty = arr[x-1]; amount = arr[x+1]; break; } } amount = amount.replace('$',''); temp = parseFloat(temp) - (parseFloat(amount) * parseInt(qty)); temp = temp.toFixed(2); temp = temp.replace('-',''); if( temp <= 0 ){ localStorage.setItem("currentprice",0.00); }else{ localStorage.setItem("currentprice",temp); } document.getElementById('newprice').innerHTML = '$' + temp; } } } function additem(name, cost, code){ name = name.replace(/\s+/g, "-"); const myDiv = document.querySelector('.basketshow'); const myName = myDiv.querySelector('#a' + name); const myValue = myDiv.querySelector('#a' + name + 1); let qty; let code1; if(myValue !== null){ const code
相关产品推荐
相关产品推荐

