Django模板JS适配多类商品购物车功能故障排查
电商购物车跨类别添加报错问题排查与解决
问题描述
基于Django开发类似amazon.in、flipkart.com的电商Web应用,使用通用模板展示各类别商品页面,通过嵌入JS结合LocalStorage实现“加入购物车”功能。出现以下问题:
- 首次进入商品页面点击“加入购物车”,JS正常执行,商品成功存入LocalStorage;
- 返回商品列表页进入另一类别商品页面后,点击按钮无响应,控制台抛出Uncaught TypeError错误,无法添加商品;
- 清空LocalStorage后可再次正常添加,但切换类别后又触发相同错误。
相关代码
商品视图模板代码(含嵌入JS)
{% extends 'MenuCategory/Navigation_bar.html' %} {% block title %} {{Category.Item_Category}} {% endblock %} {% block style %} {% endblock %} {% block head %} {% endblock %} {% block body %} <div class="container-fluid mt-3"> <div class="list-group"> {% for item in Content %} <a href="#" class="list-group-item list-group-item-action" aria-current="true"> <div class="row"> <div class="col-1 d-flex align-items-center"> <img src="/media/{{item.Item_Image}}" class="rounded img-fluid" width="150px" height="150px"> </div> <div class="col-8"> <div class="d-flex w-100 row"> <h5 id="nameby{{Category.Item_Category}}Product{{item.Item_ID}}" class="mb-1">{{item.Item_Name}}</h5> <div class="d-flex w-100 row"> <p class="mb-1">{{item.Item_Description}}</p> </div> <div class="d-flex w-100 row"> <small id="PriceOf{{Category.Item_Category}}Product{{item.Item_ID}}">{{item.Item_Price}}</small> </div> </div> </div> <div class=" col-3 d-flex justify-content-end align-items-center mr-2"> <span id="btnspan{{Category.Item_Category}}Product{{item.Item_ID}}" class="AddBtn"> <button id="{{Category.Item_Category}}Product{{item.Item_ID}}" class="btn btn-primary {{Category.Item_Category}}CartButton">Add to Cart</button> </span> </div> </div> </a> {% endfor %} </div> </div> {% endblock %} {% block script %} document.getElementById("NavbarMainHeading").innerHTML="{{Category.Item_Category}}"; function updateCart(Cart) { for (let item in Cart) { console.log(item) document.getElementById('btnspan' + item).innerHTML = `<button id="minus${item}" class="btn btn-primary minus">-</button><span id="val${item}">${Cart[item][0]}</span><button id="plus${item}" class="btn btn-primary plus">+</button>` } localStorage.setItem('Cart', JSON.stringify(Cart)) console.log(localStorage.getItem('Cart')) } if (localStorage.getItem('Cart') == null) { var Cart = {}; } else { Cart = JSON.parse(localStorage.getItem('Cart')) updateCart(Cart) } let btns = document.getElementsByClassName('{{Category.Item_Category}}CartButton'); btns = Array.from(btns); for (let i = 0; i < btns.length; i++) { btns[i].addEventListener('click', function() { var idstr = this.id.toString(); if (Cart[idstr] != undefined) { Cart[idstr][0] = Cart[idstr][0] + 1; } else { name = document.getElementById("nameby" + idstr).innerHTML; price = document.getElementById("PriceOf" + idstr).innerHTML; quantity = 1; Cart[idstr] = [quantity, name, parseInt(price)]; } updateCart(Cart) }) } {% endblock %}
urls.py代码
from django.urls import path,include from . import views urlpatterns = [ # path('admin/', admin.site.urls), path('',views.CategoryPage,name='MenuCategoryPage'), path('Category/<str:Variety_Name>',views.Category_Items,name='CategoryItems') ]
views.py代码
from django.shortcuts import render from django.http import HttpResponse from .models import Varieties,CategoryItems def Category_Items(request,Variety_Name): print(f"variety name {Variety_Name}") post=CategoryItems.objects.filter(Item_Category=Variety_Name) Category=None print(len(post)) if len(post) >= 1: Category=post[0] content={'Content':post,'Category':Category} return render(request,'MenuCategory/Product_List.html',content)
models.py代码
from django.db import models # Create your models here. class Varieties(models.Model): VarietyID=models.AutoField(primary_key=True) Variety_Name=models.CharField(max_length=50,default='Variety name should be within 50 characters.') Variety_Image=models.ImageField(default='') def __str__(self): return self.Variety_Name class CategoryItems(models.Model): Item_ID=models.AutoField(primary_key=True) Item_Category=models.CharField(max_length=50,default="Variety Name and Category Name must be same.") Item_SubCategory=models.CharField(max_length=50,default="SubCategory Name") Item_Image=models.ImageField(default='') Item_Name=models.CharField(max_length=50,default='Ex: Paneer Pratha') Item_Price=models.IntegerField() Item_Description=models.CharField(max_length=1000,default='Write Something about speciality of the Product.') def __str__(self): return f"{self.Item_Name} - {self.Item_Category}"
错误情况
- 购物车已有商品时添加其他类别商品,控制台报错:

- LocalStorage为空时可正常添加商品:

问题原因
核心问题在updateCart函数:页面加载时会遍历LocalStorage中所有购物车商品,尝试修改对应btnspan{itemId}元素的innerHTML。但当前页面仅显示当前类别的商品,其他类别的商品DOM元素不存在,调用document.getElementById('btnspan' + item)返回null,执行.innerHTML时抛出TypeError: Cannot set properties of null (setting 'innerHTML'),导致后续JS代码终止,新的添加购物车事件监听无法正常工作。
解决方案
修改updateCart函数,仅对当前页面存在的DOM元素进行更新,跳过不存在的元素:
function updateCart(Cart) { for (let item in Cart) { console.log(item) const btnSpan = document.getElementById('btnspan' + item); // 仅在元素存在时更新内容 if (btnSpan) { btnSpan.innerHTML = `<button id="minus${item}" class="btn btn-primary minus">-</button><span id="val${item}">${Cart[item][0]}</span><button id="plus${item}" class="btn btn-primary plus">+</button>`; } } localStorage.setItem('Cart', JSON.stringify(Cart)) console.log(localStorage.getItem('Cart')) }
额外优化购物车数据初始化逻辑,避免解析失败导致的异常:
// 替换原Cart初始化代码 let Cart = {}; if (localStorage.getItem('Cart')) { try { Cart = JSON.parse(localStorage.getItem('Cart')); updateCart(Cart); } catch (e) { console.error('解析购物车数据失败', e); localStorage.removeItem('Cart'); } }
修改后,切换类别页面时只会更新当前页面存在的商品按钮,不会因找不到DOM元素报错,新的添加购物车按钮可正常绑定事件。
内容的提问来源于stack exchange,提问作者Rahul Jat
相关产品推荐
相关产品推荐

