价格计算交互问题求助:折扣输入累加异常与NaN问题
价格计算与显示问题修复
问题描述
- 页面重载后可正常显示选中treatment的总价,但在相对折扣输入框输入数值时,每次按键都会基于当前显示总价累加输入值(如初始总价为7,输入11时会先计算7+1=8,再计算8+11=19,而非预期的折扣后价格),导致计算结果错误。
- 当使用绝对折扣输入框且相对折扣输入框为空时,计算结果出现NaN值。
相关代码
HTML
<div class="mb-3"> <div for="treatment" class="form-label">List treatments</div> @foreach ($treatments as $treatment) <input class="checkp" type="checkbox" id="{{$treatment->title}}" data-price="{{$treatment->price}}" name="treatments[]" value="{{$treatment->id}}" @if (count($quote->treatments->where('id', $treatment->id))) checked @endif> <label for="{{$treatment->title}}"> {{$treatment->title}} - </label><span class="price"> {{$treatment->price}}</span><br> @endforeach <p class="mt-5">Total price: <span id="total-price"></span></p> </div> <div class="mb-3"> <label for="discount" class="form-label">Discount</label> <div class="form-check my-2 mb-3"> <input class="form-check-input" type="radio" name="discount" id="flexRadioNoDisconunt" value="nodiscount" checked> <label class="form-check-label" for="flexRadioNoDisconunt"> No discount </label> </div> <div class="form-check my-2 mb-3"> <input class="form-check-input" type="radio" name="discount" id="flexRadioRelativeDisconunt" value="relativediscount"> <label class="form-check-label" for="flexRadioRelativeDisconunt"> Relative discount (in %)</label> <input type="number" id="inputrelativediscount" class="form-control p-3 inputs selectorelative" min="0" max="100" name="relativediscount" value="{{$quote->relativediscount }}"> </div> <div class="form-check my-2 mb-3"> <input class="form-check-input" type="radio" name="discount" id="flexRadioAbsoluteDisconunt" value="absolutediscount"> <label class="form-check-label" for="flexRadioAbsoluteDisconunt"> Absolute discount (in €)</label> <input type="number" id="inputabsolutediscount" class="form-control p-3 inputs selectorabsolute" min="0" name="absolutediscount" value="{{ $quote->absolutediscount }}"> </div>
JavaScript(原始代码)
document.querySelectorAll('input[type=checkbox]').forEach((elem) => elem.addEventListener("click", function (event) { if (event.target.checked) { sum = sum + parseInt(elem.getAttribute('data-price')) } else { let el = parseInt(elem.getAttribute('data-price')) sum = sum - el } //console.log(sum); document.getElementById("total-price").innerHTML = sum; })); document.querySelectorAll('.inputs').forEach((elem) => elem.addEventListener("keyup", function () { if (document.querySelector('.selectorelative')) { document.getElementById("total-price").innerHTML = parseInt(document.getElementById("total-price").innerHTML) + parseInt(document.querySelector('.selectorelative').value); } else { document.getElementById("total-price").innerHTML = parseInt(document.getElementById("total-price").innerHTML) + parseInt(document.querySelector('.selectorabsolute').value); } } ))
修复方案
核心问题分析
- 折扣计算没有基于原始总价,而是直接修改显示的总价,导致每次按键都叠加计算,结果错误。
- 输入框为空时
parseInt()返回NaN,与数值运算后导致最终结果为NaN。 - 没有区分当前选中的折扣类型,错误地同时处理两种折扣输入框。
修改后的JavaScript代码
// 初始化原始总价和当前总价 let originalTotal = 0; let currentTotal = 0; // 页面加载时先计算初始选中的treatment总价 document.querySelectorAll('input[type=checkbox]:checked').forEach(elem => { originalTotal += parseInt(elem.getAttribute('data-price')); }); currentTotal = originalTotal; document.getElementById("total-price").innerHTML = currentTotal; // 复选框点击事件:更新原始总价和当前总价 document.querySelectorAll('input[type=checkbox]').forEach((elem) => elem.addEventListener("click", function (event) { const price = parseInt(elem.getAttribute('data-price')); if (event.target.checked) { originalTotal += price; } else { originalTotal -= price; } // 重新计算折扣后的总价 calculateDiscount(); })); // 折扣输入框和单选按钮的事件监听 document.querySelectorAll('.inputs, input[name="discount"]').forEach(elem => { elem.addEventListener("input", calculateDiscount); }); // 统一计算折扣的函数 function calculateDiscount() { const selectedDiscount = document.querySelector('input[name="discount"]:checked').value; let discountValue = 0; switch(selectedDiscount) { case "relativediscount": // 处理相对折扣,为空时默认0,避免NaN discountValue = parseInt(document.getElementById("inputrelativediscount").value) || 0; currentTotal = originalTotal - (originalTotal * discountValue / 100); break; case "absolutediscount": // 处理绝对折扣,为空时默认0 discountValue = parseInt(document.getElementById("inputabsolutediscount").value) || 0; currentTotal = originalTotal - discountValue; // 确保总价不低于0 currentTotal = Math.max(currentTotal, 0); break; default: // 无折扣时直接显示原始总价 currentTotal = originalTotal; break; } // 更新显示的总价,保留两位小数(可选,根据需求调整) document.getElementById("total-price").innerHTML = currentTotal.toFixed(2); }
修复说明
- 保留原始总价:新增
originalTotal变量存储未应用折扣的总价,所有折扣计算都基于这个值,避免叠加错误。 - 统一计算逻辑:封装
calculateDiscount()函数,根据选中的折扣类型重新计算总价,每次输入或单选按钮变化时触发。 - 处理空输入:使用
|| 0确保输入框为空时取0,避免NaN问题。 - 优化事件监听:同时监听折扣输入框和单选按钮的变化,确保切换折扣类型时立即更新总价。
- 边界处理:绝对折扣时确保总价不低于0,避免出现负数。
内容的提问来源于stack exchange,提问作者Sarah
相关产品推荐
相关产品推荐

