You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

页面重载后购物车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 x
  • window.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
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 23:43:15