如何在Django循环模板中用JavaScript计算多组输入值
问题解决方案
问题根源
- 循环渲染时重复使用相同
id,违反HTML规范;document.querySelector仅返回第一个匹配元素,导致所有组共用第一组的输入值。 - 输入框class均为
shares,无法区分「投注金额」和「份额」,取值逻辑混乱。 - 函数定义在循环内部,重复创建同名函数,引发覆盖问题。
- NaN判断逻辑错误:
potential_win === isNan写法完全错误,isNaN是全局函数,需传入计算值进行判断。
修复后的完整代码
Django模板部分
{% for p in prediction.prediction_data.all %} <div class="mid-area" data-group-id="{{ forloop.counter }}"> <div class="single-area"> <div class="item-title d-flex align-items-center justify-content-between"> <span>Choose Stake Amount</span> </div> <div class="d-flex in-dec-val"> <input type="number" required value="{{ p.amount }}" name="amount" placeholder="amount" class="amount-input" onkeyup="CalculateNewBalance(this)" /> <div class="btn-area"> <button class="plus" type="button"> <img src="{% static 'assets/images/icon/up-arrow.png' %}" alt="icon" /> </button> <button class="minus" type="button"> <img src="{% static 'assets/images/icon/down-arrow.png' %}" alt="icon" /> </button> </div> </div> <p id="error-div-{{ forloop.counter }}" class="mt-2"></p> </div> <div class="single-area quick-amounts"></div> <div class="single-area quick-amounts"> <div class="item-title d-flex align-items-center"> <p>Choose <b>Shares</b> Amount</p> </div> <div class="d-flex in-dec-val"> <input type="number" required value="1" name="shares" placeholder="shares" class="shares-input" onkeyup="CalculateNewBalance(this)" /> <div class="btn-area"> <button class="pldus" type="button"> <img src="{% static 'assets/images/icon/up-arrow.png' %}" alt="icon" /> </button> <button class="mindus" type="button"> <img src="{% static 'assets/images/icon/down-arrow.png' %}" alt="icon" /> </button> </div> </div> </div> <div class="single-area smart-value"> <div class="item-title d-flex align-items-center"> <p class="mdr text-capitalize">Potential win</p> </div> <div class="contact-val d-flex align-items-center"> <span style="font-size: 24px;" class="potential-win">$0.00</span><br /> </div> </div> </div> {% endfor %} <!-- 脚本移到循环外,只定义一次 --> <script> function CalculateNewBalance(element) { // 找到当前输入框所在的组容器 const group = element.closest('.mid-area'); // 在当前组内获取对应的输入框和结果元素 const stakeInput = group.querySelector('.amount-input'); const sharesInput = group.querySelector('.shares-input'); const potentialWinEl = group.querySelector('.potential-win'); // 处理输入值,空值或非数字转为0 const stakeAmount = parseFloat(stakeInput.value) || 0; const sharesAmount = parseInt(sharesInput.value) || 0; // 计算潜在收益 let potentialWinValue = stakeAmount * sharesAmount; // 处理NaN或无效计算,转为0.00 if (isNaN(potentialWinValue)) { potentialWinValue = 0; } // 格式化显示为带$的两位小数 potentialWinEl.innerHTML = `$${potentialWinValue.toFixed(2)}`; } </script>
关键修改说明
- 唯一组标识:给每个
.mid-area添加data-group-id(用forloop.counter生成唯一值),同时修改错误提示框的id为error-div-{{ forloop.counter }},避免重复id。 - 区分输入框class:将投注金额输入框的class改为
amount-input,份额输入框改为shares-input,确保能精准定位元素。 - 函数移至循环外:避免重复定义
CalculateNewBalance函数,引发变量覆盖问题。 - 传递当前元素:
onkeyup="CalculateNewBalance(this)"将触发事件的输入框传入函数,通过closest('.mid-area')定位到当前组,确保每个组独立计算。 - 输入值容错处理:用
|| 0将空值或非数字输入转为0,避免计算出现NaN。 - 正确的NaN判断:使用
isNaN(potentialWinValue)判断计算结果是否无效,同时用toFixed(2)保证金额显示为两位小数。
内容的提问来源于stack exchange,提问作者Destiny Franks
相关产品推荐
相关产品推荐

