跨页面传递Total时出现Cannot read properties of null (reading '0')错误排查
问题描述
我已实现从商品页向结账页传递商品数据并计算总价,现在需要将结账页的total(总价)和subtotal(小计)传递至作为支付页的index页面,但支付页无法显示该数值,控制台报错:Uncaught TypeError: Cannot read properties of null (reading '0') at index.html:41:79。
商品页代码
<section id="prodetails" class="section-p1"> <div class="productcontainer" id="enjoy"> <div class="single-pro-image"> <img src="../data/high.png" width="100%" id="product-image" class="product-img"> </div> <div class="single-pro-details" action="C:\s\starter-ruby\client\checkout.html"> <h4 class="product-title" id="title">Enjoy</h4> <h2 id="price" class="price">$20</h2> <h3>Select Licence</h3> <select id="select" class="licence"> <option>MP3</option> <option>Tagged Wav</option> <option>Un-Tagged Wav</option> <option>Stems</option> <option>Exlusive</option> </select> <script> let select = document.getElementById('select'); let price = document.getElementById('price'); // Prices let prices = { "MP3": '$20', "Tagged Wav": '$27', "Un-Tagged Wav": '$30', "Stems": '$120', "Exlusive": '$300' } // When the value of select changes, this event listener fires and changes the text content of price to the coresponding value from the prices object select.addEventListener('change', () => { price.textContent = prices[select.value]; }); </script> <button class="add-cart">Add To Cart <i class='bx bx-cart-add add-cart'></i></button> <h4>Product Details</h4> <span>Lil Tjay x Trap Type Beat - "Enjoy" in key D# Minor and 160 BPM,It has vibe of Lil Tjay , Pop Smoke and more , Prices are great for this type of beat;Tagged Mastered MP3 for $25,$27 for Tagged Unmastered Wav,$30 for Untagged unmastered Wav,$70 for Stems and $120 for Exlusive</span> </div> <div id="audio"> <audio controls style="width:100%" id="audio-clip"> <source src="Audio/Enjoy 160 x D sharp minor.mp3" type="audio/mp3"> </audio> </div> </section> <script> var selectedItems = []; const addToCartButton = document.querySelector('.add-cart'); if (addToCartButton) { addToCartButton.addEventListener('click', () => { const productTitle = document.querySelector('#title').textContent; const productPrice = document.querySelector('#price').textContent; const selectedLicense = document.querySelector('#select').value; const productImage = document.getElementById('product-image'); const ImageSrc = productImage.src; const audioElement = document.getElementById('audio-clip'); const audioSrc = audioElement.src; const cartItem = { title: productTitle, price: productPrice, license: selectedLicense, image: ImageSrc, audio: audioSrc }; let selectedItems = JSON.parse(localStorage.getItem('selectedItems')) || []; // Check if the item already exists in the cart let existingItemIndex = selectedItems.findIndex(item => item.title === productTitle && item.license === selectedLicense); if (existingItemIndex > -1) { // If the item already exists, update the license selectedItems[existingItemIndex].license = selectedLicense; } else { // If the item doesn't exist, add it to the cart selectedItems.push(cartItem); } console.log(selectedItems); localStorage.setItem('selectedItems', JSON.stringify(selectedItems)); }); } </script>
结账页代码
<h2 style="text-align:center;">Checkout</h2> <div id="product-items"> <p style="text-align:center;"><span id="added-products"></p> <div class="product-container"> <div class="cart-items"></div> </div> <button id="clear-button">CLEAR ITEMS - REDIRECT TO HOME</button> <script> document.getElementById("clear-button").addEventListener("click", function() { const cartItemsDiv = document.querySelector(".cart-items"); cartItemsDiv.innerHTML = ""; // clear the HTML content of the cart-items div const subtotalSpan = document.getElementById("subtotal"); const totalSpan = document.getElementById("total"); subtotalSpan.innerHTML = ""; totalSpan.innerHTML = "$0"; // set the total price to $0 localStorage.removeItem("selectedItems"); // remove the selected items from localStorage clearCartItems(); }); </script> <!--fix the error that how much items in one cart is,e.g if add 2 mp3 and that it does not display that both 2 items for (var i = 0; i < cartProducts.length; i++) { if (cartProducts[i].title === title && cartProducts[i].option === licence) { alert('You have already added this product to your cart with the same option.'); return; } } --> </div> <div class="total"> <form action="index.html" class="total"> <h3 style="text-align:center; display: none;">Subtotal: <br><span id="subtotal"></span></h3> <h3 style="text-align:center;">Total: <br><span id="total">$0</span></h3> <a href="index.html"><button type="submit" class="buy-btn" style="background-color: rgb(29, 4, 216);">Continue to purchase</button></a> <a href="index.html" onclick="alert('You will be redirected to the home page')"><button style="background-color: rgb(216, 4, 4);">Cancel</button></a> </div> </form> <!--It does clear but wonder , make that you cant click on button if that function is done--> </body> <script> const cartItemsDiv = document.querySelector(".cart-items"); const storedCartItem = localStorage.getItem("selectedItems"); let subtotal = 0; const continueButton = document.getElementById("buy-btn"); const clearButton = document.getElementById("clear-button"); function clearCartItems() { // Clear the HTML content of the cart-items div const cartItemsDiv = document.querySelector(".cart-items"); cartItemsDiv.innerHTML = ""; // Set the subtotal and total to $0 const subtotalSpan = document.getElementById("subtotal"); const totalSpan = document.getElementById("total"); subtotalSpan.innerHTML = ""; totalSpan.innerHTML = "$0"; // Remove the selected items from localStorage localStorage.removeItem("selectedItems"); alert("Added items will be cleared."); // Change the URL to the index page and prevent going to the checkout page window.location.href = "sproduct6.html"; history.replaceState(null, "", window.location.href); // Update the UI document.getElementById("added-products").innerHTML = "You have no items in your cart!"; document.getElementById("buy-btn").style.display = "none"; document.getElementById("clear-button").style.display = "none"; if (cartItemCount == 0) { setTimeout(function() { alert("You have no items in your cart. Let's get back to product page."); window.location.href = ('sproduct6.html'); }, 50); // 3 second delay document.getElementById("added-products").innerHTML = "You have no items in your cart!"; continueButton.style.display = "none"; clearButton.style.display = "none"; // Save the visibility state of the buttons localStorage.setItem("buttonsVisible", "false"); } else { document.getElementById("added-products").innerHTML = "YOU ADDED THIS PRODUCTS"; } } if (storedCartItem) { const cartItem = JSON.parse(storedCartItem); // Parse the storedCartItem string into an array for (let i = 0; i < cartItem.length; i++) { const cartItemElement = document.createElement("div"); cartItemElement.innerHTML = ` <hr /> <h3>${cartItem[i].title}</h3> <p>Price: ${cartItem[i].price}</p> <p>License: ${cartItem[i].license}</p> <img src="${cartItem[i].image}" width='30%'/><br> <audio controls style="width:50%;"> <source src="${cartItem[i].audio}" type="audio/mp3"> </audio> `; // ADD DELETE OPTION cartItemsDiv.appendChild(cartItemElement); const price = Number(cartItem[i].price.replace("$", "")); // Parse price as a number and remove dollar sign subtotal += price; // MAKE REPLACE TITLE TO YOU HAVE NO ITEMS IN YOUR CART } const subtotalElement = document.querySelector("#subtotal"); subtotalElement.textContent = `$${subtotal.toFixed(2)}`; const totalElement = document.querySelector("#total"); const total = subtotal; totalElement.textContent = `$${total.toFixed(2)}`; const totalPriceInput = document.querySelector("#total_price"); totalPriceInput.value = total.toFixed(2); } function passtotal(){ var total = document.getElementById('total').value; var subtotal = document.getElementById('subtotal').value; localStorage.setItem("values", JSON.stringify({total: total, subtotal: subtotal})); return false; } </script> </html>
支付页(index.html)代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Stripe Sample</title> <meta name="description" content="A demo of Stripe" /> <link rel="icon" href="favicon.ico" type="image/x-icon" /> <link rel="stylesheet" href="css/normalize.css" /> <link rel="stylesheet" href="css/global.css" /> <script src="https://js.stripe.com/v3/"></script> <script src="./payment.js"></script> </head> <body> <div class="sr-root"> <span id="total"></span> <span id="subtotal"></span> <div class="sr-main"> <h1>Pay with a bunch of payment option</h1> <form id="payment-form" method="POST"> <input type="text" name="email" id="email" placeholder="E-Mail" required> <input type="text" name="name" id="name" placeholder="Full Name" required> <div id="payment-element"></div> <button>Pay</button><!--Make functional--> <!--Make total price hidden and that total of this is same as in checkout and that its connected to ruby--> <div id="error-messages"></div> </form> </div> </div> <script> var value = localStorage.getItem("value"); if (value !== null && value !== undefined) { document.getElementById("total").innerHTML = value[0]; } else { alert('something went wrong...Can you please try again') } document.getElementById("total").innerHTML=localStorage.getItem("value")[0]; </script> </body> </html>
错误原因分析
- localStorage键名不匹配:结账页存的是
"values",但支付页取的是"value",导致获取结果为null,再访问[0]触发类型错误。 - DOM元素值获取错误:结账页的total和subtotal是
<span>标签,用.value无法获取内容,应该用.textContent。 - 数据解析逻辑错误:存入localStorage的是JSON对象,支付页直接把字符串当数组访问
[0],未做JSON解析。 - 存储函数未触发:结账页的
passtotal函数没有被调用,导致数据根本没存入localStorage。
修复方案
1. 修复结账页代码
修改passtotal函数
function passtotal(){ // 用textContent获取span的文本内容 var total = document.getElementById('total').textContent; var subtotal = document.getElementById('subtotal').textContent; localStorage.setItem("values", JSON.stringify({total: total, subtotal: subtotal})); return true; // 允许表单正常跳转 }
修改提交按钮
移除外层<a>标签,给按钮绑定函数触发事件:
<button type="submit" class="buy-btn" style="background-color: rgb(29, 4, 216);" onclick="return passtotal();">Continue to purchase</button>
2. 修复支付页代码
替换原有的script代码,正确解析并展示数据:
<script> const storedValues = localStorage.getItem("values"); if (storedValues) { const { total, subtotal } = JSON.parse(storedValues); document.getElementById("total").textContent = `总价: ${total}`; document.getElementById("subtotal").textContent = `小计: ${subtotal}`; } else { alert('数据传递失败,请返回结账页重试'); } </script>
额外优化建议
- 结账页可判断购物车为空时禁用支付按钮,避免空数据跳转
- 支付页完成支付后,清理localStorage中的
"values"和"selectedItems",防止残留数据干扰后续操作 - 增加数据格式验证,确保总价和小计为有效数值后再展示
内容的提问来源于stack exchange,提问作者Danijel Krnic
相关产品推荐
相关产品推荐

