Firebase+Cookie购物车添加功能报错:Cannot read properties of null(quantity)
问题排查与修复方案
核心错误原因
控制台抛出的Cannot read properties of null (reading 'quantity')错误,根源在于以下几处代码逻辑问题:
addCart函数中未定义products变量:尝试复制products但该变量从未声明,导致productsCopy为空数组,filter后返回undefined,给quantity赋值时触发空值读取错误。addCartToHTML函数遍历对象错误:遍历了Firebase中的所有商品,而非购物车中已添加的商品,并且错误访问商品本身的quantity属性(商品数据里没有这个字段,购物车项才会存储)。changeQuantity函数缺少空值判断:当购物车项被删除后,直接访问listCart[$idProduct].quantity会触发空值错误。
具体修复步骤
1. 修复addCart函数
从Firebase快照中直接获取商品数据并筛选目标商品,不再依赖未定义的变量:
function addCart($idProduct){ firebase.database().ref('Products/').once('value').then(function(snapshot){ const products = snapshot.val(); // 如果该商品不在购物车中 if(!listCart[$idProduct]) { // 从Firebase数据中筛选目标商品 const targetProduct = Object.values(products).filter(item => item.pid == $idProduct)[0]; if(targetProduct){ listCart[$idProduct] = {...targetProduct, quantity: 1}; } }else{ // 如果该商品已在购物车中,仅增加数量 listCart[$idProduct].quantity++; } document.cookie = "listCart=" + JSON.stringify(listCart) + "; expires=Thu, 31 Dec 2025 23:59:59 UTC; path=/;"; addCartToHTML(); }); }
2. 重构addCartToHTML函数
只遍历购物车中的商品,正确读取购物车项的quantity属性:
function addCartToHTML(){ firebase.database().ref('Products/').once('value').then(function(snapshot){ const listCartHTML = document.querySelector('.listCart'); listCartHTML.innerHTML = ''; const products = snapshot.val(); const totalHTML = document.querySelector('.totalQuantity'); let totalQuantity = 0; // 遍历购物车中的商品 for(const [pid, cartItem] of Object.entries(listCart)){ if(cartItem){ const product = Object.values(products).find(item => item.pid == pid); if(product){ const newCart = document.createElement('div'); newCart.classList.add('item'); newCart.innerHTML = `<img src="${product.image}"> <div class="content"> <div class="name">${product.pname}</div> <div class="price">$${product.price} / 1件商品</div> </div> <div class="quantity"> <button onclick="changeQuantity(${pid}, '-')">-</button> <span class="value">${cartItem.quantity}</span> <button onclick="changeQuantity(${pid}, '+')">+</button> </div>`; listCartHTML.appendChild(newCart); totalQuantity += cartItem.quantity; } } } totalHTML.innerText = totalQuantity; }); }
3. 修复changeQuantity函数
增加空值判断,避免访问不存在的购物车项:
function changeQuantity($idProduct, $type){ // 先判断购物车项是否存在 if(!listCart[$idProduct]) return; switch ($type) { case '+': listCart[$idProduct].quantity++; break; case '-': listCart[$idProduct].quantity--; // 如果数量<=0则从购物车中移除商品 if(listCart[$idProduct].quantity <= 0){ delete listCart[$idProduct]; } break; default: break; } document.cookie = "listCart=" + JSON.stringify(listCart) + "; expires=Thu, 31 Dec 2025 23:59:59 UTC; path=/;"; addCartToHTML(); }
完整修正后的index.js代码
firebase.initializeApp(config2); window.onload=function(){ this.addDataToHTML(); } let iconCart = document.querySelector('.iconCart'); let cart = document.querySelector('.cart'); let container = document.querySelector('.container'); let close = document.querySelector('.close'); iconCart.addEventListener('click', function(){ if(cart.style.right === '-100%'){ cart.style.right = '0'; container.style.transform = 'translateX(-400px)'; }else{ cart.style.right = '-100%'; container.style.transform = 'translateX(0)'; } }) close.addEventListener('click', function (){ cart.style.right = '-100%'; container.style.transform = 'translateX(0)'; }) // 在列表中显示产品数据 function addDataToHTML(){ firebase.database().ref('Products/').once('value').then(function(snapshot){ let listProductHTML = document.querySelector('.listProduct'); listProductHTML.innerHTML = ''; const data = snapshot.val(); if(data != null){ for(const [key,value] of Object.entries(data)){ let newProduct = document.createElement('div'); newProduct.classList.add('item'); newProduct.innerHTML = `<img src="${value.image}" alt=""> <h2>${value.pname}</h2> <div class="price">$${value.price}</div> <button onclick="addCart(${value.pid})">加入购物车</button>`; listProductHTML.appendChild(newProduct); } } }); } let listCart = {}; // 改为对象更适合按pid存储 function checkCart(){ const cookieValue = document.cookie .split('; ') .find(row => row.startsWith('listCart=')); if(cookieValue){ listCart = JSON.parse(cookieValue.split('=')[1]); }else{ listCart = {}; } } checkCart(); function addCart($idProduct){ firebase.database().ref('Products/').once('value').then(function(snapshot){ const products = snapshot.val(); if(!listCart[$idProduct]){ const targetProduct = Object.values(products).filter(item => item.pid == $idProduct)[0]; if(targetProduct){ listCart[$idProduct] = {...targetProduct, quantity: 1}; } }else{ listCart[$idProduct].quantity++; } document.cookie = "listCart=" + JSON.stringify(listCart) + "; expires=Thu, 31 Dec 2025 23:59:59 UTC; path=/;"; addCartToHTML(); }); } addCartToHTML(); function addCartToHTML(){ firebase.database().ref('Products/').once('value').then(function(snapshot){ const listCartHTML = document.querySelector('.listCart'); listCartHTML.innerHTML = ''; const products = snapshot.val(); const totalHTML = document.querySelector('.totalQuantity'); let totalQuantity = 0; for(const [pid, cartItem] of Object.entries(listCart)){ if(cartItem){ const product = Object.values(products).find(item => item.pid == pid); if(product){ const newCart = document.createElement('div'); newCart.classList.add('item'); newCart.innerHTML = `<img src="${product.image}"> <div class="content"> <div class="name">${product.pname}</div> <div class="price">$${product.price} / 1件商品</div> </div> <div class="quantity"> <button onclick="changeQuantity(${pid}, '-')">-</button> <span class="value">${cartItem.quantity}</span> <button onclick="changeQuantity(${pid}, '+')">+</button> </div>`; listCartHTML.appendChild(newCart); totalQuantity += cartItem.quantity; } } } totalHTML.innerText = totalQuantity; }); } function changeQuantity($idProduct, $type){ if(!listCart[$idProduct]) return; switch ($type) { case '+': listCart[$idProduct].quantity++; break; case '-': listCart[$idProduct].quantity--; if(listCart[$idProduct].quantity <= 0){ delete listCart[$idProduct]; } break; default: break; } document.cookie = "listCart=" + JSON.stringify(listCart) + "; expires=Thu, 31 Dec 2025 23:59:59 UTC; path=/;"; addCartToHTML(); }
内容的提问来源于stack exchange,提问作者Argus Gale
相关产品推荐
相关产品推荐

