点击产品项后收藏图标重复存储数据的问题及解决方案
Hey there! Let's break down what's going wrong here and fix it properly.
问题场景
When you click #qv1, #qv2, or #qv3 to switch product previews, the favorite icon (#saveProd) is supposed to save only the current product to localStorage. But right now, if you click #qv1 first, then #qv3, clicking the favorite icon saves all three products (product1, product2, product3) to localStorage at once.
相关代码
HTML
<span><i style="cursor: pointer;" id="saveProd" class="fa fa-heart-o" aria-hidden="true"></i></span>
当前jQuery代码
$(document).ready(function(){ $("#qv1").click(function(e){ $("#qvimage").attr({"src":"img/product/1.jpg"}); $("#qvbname").html("Luceat Pro"); $("#qvpname").html("SELECTED Black Denim Jacket"); $("#qvprice").html("5,900.00 €"); $("#qvdis").html(" "); $("#qvoff").html("Offers : "); $("#saveProd").click(function(e){ $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); $.localStorage("p1","product1"); }); value = $.localStorage('p1'); if(value == "product1"){ $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); } else { $("#saveProd").removeClass("fa-heart").addClass("fa-heart-o"); } }); }); $(document).ready(function(){ $("#qv2").click(function(e){ $("#qvimage").attr({"src":"img/product/2.jpg"}); $("#qvbname").html("Luceat Pro"); $("#qvpname").html("Black Solid Jacket"); $("#qvprice").html("<s style='color: grey; font-size: 12px;'>4,500.00 €</s> 2,250.00 €"); $("#qvdis").html(" (50% Off)"); $("#qvoff").html("Offers : Get 50% Off"); $("#saveProd").click(function(e){ $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); $.localStorage("p2","product2"); }); value = $.localStorage('p2'); if(value == "product2"){ $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); } else { $("#saveProd").removeClass("fa-heart").addClass("fa-heart-o"); } }); }); $(document).ready(function(){ $("#qv3").click(function(e){ $("#qvimage").attr({"src":"img/product/3.jpg"}); $("#qvbname").html("Luceat Exlusive"); $("#qvpname").html("Solid Brown Lether Jacket"); $("#qvprice").html("<s style='color: grey; font-size: 12px;'>1,000.00 €</s> 500.00 €"); $("#qvdis").html(" (50% Off)"); $("#qvoff").html("Offers : Get 50% Off"); $("#saveProd").click(function(e){ $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); $.localStorage("p3","product3"); }); value = $.localStorage('p3'); if(value == "product3"){ $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); } else { $("#saveProd").removeClass("fa-heart").addClass("fa-heart-o"); } }); });
问题根源
Every time you click a #qvX button, you're adding a new click event listener to #saveProd instead of replacing the old one. For example:
- Click
#qv1→ binds an event that savesp1 - Click
#qv3→ adds another event that savesp3 - Now
#saveProdhas two (or more) event listeners attached. When you click it, all of them run at the same time, saving all previously bound products.
解决方案
方案1:绑定新事件前先移除旧事件
快速修复:用.off('click')清除#saveProd上已有的所有点击事件,再绑定当前产品的保存逻辑。修改每个#qvX的点击处理代码:
// 在$("#qv1").click(...)内部修改 $("#saveProd").off('click').click(function(e){ $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); $.localStorage("p1","product1"); });
对#qv2和#qv3做同样修改,这样每次切换产品时,旧的收藏事件会被清除,只保留当前产品对应的逻辑。
方案2:更优雅的写法——单一事件监听+跟踪当前产品
这是更易维护的长期方案:我们只给收藏按钮绑定一次事件,同时跟踪当前选中的产品ID,避免重复绑定。
- 先给预览按钮添加自定义属性标识产品:
<!-- 示例预览按钮(根据你的实际HTML调整) --> <button id="qv1" data-product-id="p1">预览产品1</button> <button id="qv2" data-product-id="p2">预览产品2</button> <button id="qv3" data-product-id="p3">预览产品3</button>
- 重构jQuery代码:
$(document).ready(function(){ // 跟踪当前选中的产品ID let currentProductId = ''; // 统一处理所有预览按钮的点击事件 $('[id^="qv"]').click(function(e){ currentProductId = $(this).data('product-id'); // 根据产品ID更新预览内容 switch(currentProductId){ case 'p1': $("#qvimage").attr("src", "img/product/1.jpg"); $("#qvbname").text("Luceat Pro"); $("#qvpname").text("SELECTED Black Denim Jacket"); $("#qvprice").html("5,900.00 €"); $("#qvdis").html(" "); $("#qvoff").text("Offers : "); break; case 'p2': $("#qvimage").attr("src", "img/product/2.jpg"); $("#qvbname").text("Luceat Pro"); $("#qvpname").text("Black Solid Jacket"); $("#qvprice").html("<s style='color: grey; font-size: 12px;'>4,500.00 €</s> 2,250.00 €"); $("#qvdis").html(" (50% Off)"); $("#qvoff").text("Offers : Get 50% Off"); break; case 'p3': $("#qvimage").attr("src", "img/product/3.jpg"); $("#qvbname").text("Luceat Exlusive"); $("#qvpname").text("Solid Brown Lether Jacket"); $("#qvprice").html("<s style='color: grey; font-size: 12px;'>1,000.00 €</s> 500.00 €"); $("#qvdis").html(" (50% Off)"); $("#qvoff").text("Offers : Get 50% Off"); break; } // 根据localStorage更新收藏图标状态 const storedValue = $.localStorage(currentProductId); if(storedValue === `product${currentProductId.slice(1)}`){ $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); } else { $("#saveProd").removeClass("fa-heart").addClass("fa-heart-o"); } }); // 给收藏按钮绑定单一点击事件 $("#saveProd").click(function(e){ if(!currentProductId) return; // 未选中产品时不执行 $("#saveProd").removeClass("fa-heart-o").addClass("fa-heart"); $.localStorage(currentProductId, `product${currentProductId.slice(1)}`); }); });
这种写法更简洁,后续新增产品只需在switch中添加对应分支,再也不用担心重复绑定事件的问题。
内容的提问来源于stack exchange,提问作者Bhavya Sanchaniya

