ASP.NET ListView中TextBox客户端失焦事件重复触发及计算需求解决
解决方案:ListView中TextBox的onblur多次触发问题
问题根源
你给txtTokensReq设置了ClientIDMode="Static",但ListView是循环生成多行数据的,这会导致所有行的txtTokensReq、txtQty、lblTotalTokens的ID完全重复。浏览器无法区分不同行的控件,不仅会导致计算时拿错值,还会引发onblur事件被错误触发多次。
修正步骤
1. 调整ASPX控件代码
去掉不必要的ClientIDMode="Static",给控件添加专属类名用于JS定位,同时给每行包裹一个容器:
<asp:ListView runat="server" ID="lstView" GroupItemCount="1" OnItemDataBound="lstView_ItemDataBound"> <ItemTemplate> <!-- 每行包裹一个容器,用于定位当前行的控件 --> <div class="list-row"> <asp:TextBox runat="server" CssClass="inputQty txt-tokens-req" MaxLength="5" ID="txtTokensReq" Text='<%# Eval("PartToken")%>' ReadOnly="true"></asp:TextBox> <asp:TextBox runat="server" CssClass="inputQty txt-qty" MaxLength="5" ID="txtQty" Text='<%# Eval("Qty")%>' onKeypress="if(!validatenumeric(this,5)){return false;}"></asp:TextBox> <asp:Label ID="lblTotalTokens" CssClass="note-maxqty col-last lbl-total-tokens" Text='<%# Eval("TotalTokenReq")%>' runat="server"></asp:Label> </div> </ItemTemplate> </asp:ListView>
2. 编写客户端计算逻辑
通过相对定位找到当前输入框所在行的对应控件,避免全局ID查找的冲突。可以选择两种方式:
方式一:直接绑定onblur到控件
添加计算函数,在txtQty的onblur事件中传入当前控件对象:
function calculateTotalQty(el) { // 获取当前输入框所在的行容器 const row = el.closest('.list-row'); if (!row) return; // 定位当前行的Token输入框和结果标签 const tokensInput = row.querySelector('.txt-tokens-req'); const totalLabel = row.querySelector('.lbl-total-tokens'); // 取值并计算(兼容空值或非数字情况) const tokens = parseFloat(tokensInput.value) || 0; const qty = parseFloat(el.value) || 0; const total = tokens * qty; // 更新结果标签 totalLabel.textContent = total.toFixed(2); // 可根据需求调整小数位数 }
然后修改txtQty的属性,添加onblur:
<asp:TextBox runat="server" CssClass="inputQty txt-qty" MaxLength="5" ID="txtQty" Text='<%# Eval("Qty")%>' onKeypress="if(!validatenumeric(this,5)){return false;}" onblur="calculateTotalQty(this)"></asp:TextBox>
方式二:事件委托(更优雅)
不在每个控件上写事件,而是把事件绑定到ListView容器上,通过事件冒泡触发逻辑:
// 页面加载完成后绑定事件委托 document.addEventListener('DOMContentLoaded', function() { const listView = document.getElementById('<%= lstView.ClientID %>'); listView.addEventListener('blur', function(e) { // 只处理txt-qty控件的失焦事件 if (e.target.classList.contains('txt-qty')) { calculateTotalQty(e.target); } }, true); }); function calculateTotalQty(el) { const row = el.closest('.list-row'); if (!row) return; const tokensInput = row.querySelector('.txt-tokens-req'); const totalLabel = row.querySelector('.lbl-total-tokens'); const tokens = parseFloat(tokensInput.value) || 0; const qty = parseFloat(el.value) || 0; const total = tokens * qty; totalLabel.textContent = total.toFixed(2); }
效果说明
两种方式都能确保:
- 每个行的控件被独立识别,不会出现ID冲突
- 失焦事件只会触发当前输入框对应的计算逻辑,不会多次执行
内容的提问来源于stack exchange,提问作者GVMK
相关产品推荐
相关产品推荐

