You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 06:21:10