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

Blazor自定义InputNumber组件:数字输入限制及报错处理

解决Blazor自定义InputNumber组件的event.preventDefault报错问题

报错原因

你遇到的event.preventDefault is not a function错误,是因为Blazor传递给JS的KeyboardEventArgs是框架封装后的对象,并非浏览器原生的键盘事件对象,所以没有preventDefault()方法。而且Blazor的键盘事件本身支持通过返回布尔值来控制是否阻止默认行为,完全不需要依赖JS来处理。

修复方案

  1. 移除JS中的validateInput函数,把按键验证逻辑移到C#代码中,通过返回false来阻止非法按键的默认行为。
  2. 调整数值格式化逻辑,确保千分位用点、小数用逗号的显示格式符合需求。
  3. 优化输入值与decimal类型的转换逻辑,避免格式转换错误。

修改后的完整组件代码

@inherits InputNumber<decimal?>
@using System.Globalization
@using System.Text.RegularExpressions

<input @attributes="AdditionalAttributes"
       id="@_id"
       class="@CssClass"
       value="@_stringValue"
       @onkeydown="OnKeyDown"
       @oninput="OnInput"
       @onchange="OnValueChanged" />

<script>
    window.formatNumberInput = function (value, allowDecimals) {
        let cleanedValue = value.replace(/[^0-9.,]/g, '');
        // 统一将点替换为逗号,确保小数分隔符是逗号
        cleanedValue = cleanedValue.replace(/\./g, ',');
        let parts = cleanedValue.split(',');
        // 千分位用点分隔
        let integerPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
        let formattedValue = integerPart;

        if (allowDecimals && parts.length > 1) {
            // 保留两位小数
            formattedValue += ',' + parts[1].substring(0, 2);  
        }

        return formattedValue;
    }
</script>

@code {
    private string _id { get; set; } = Guid.NewGuid().ToString();
    private string? _stringValue;
    private string? _currentValue;

    [Inject] IJSRuntime _jsRuntime { get; set; }

    // 自定义格式:千分位用点,小数用逗号
    [Parameter] public string FormatString { get; set; } = "#.##0,00";
    [Parameter] public bool AllowDecimals { get; set; } = true;

    protected override void OnParametersSet()
    {
        if (Value.HasValue)
        {
            // 使用自定义文化格式来匹配显示需求
            var customCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
            customCulture.NumberFormat.NumberGroupSeparator = ".";
            customCulture.NumberFormat.NumberDecimalSeparator = ",";
            _stringValue = Value.Value.ToString(FormatString, customCulture);
        }
        else
        {
            _stringValue = null;
        }
    }

    private bool OnKeyDown(KeyboardEventArgs e)
    {
        // 允许的按键列表
        var allowedKeys = new[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                                 "Backspace", "Tab", "Enter", "ArrowLeft", "ArrowRight" };

        if (allowedKeys.Contains(e.Key))
        {
            return true;
        }

        // 处理小数分隔符
        if (AllowDecimals && (e.Key == "," || e.Key == "."))
        {
            // 确保输入框中最多只有一个小数分隔符
            if (_stringValue?.Contains(',') == false)
            {
                return true;
            }
        }

        // 阻止非法按键的默认行为
        return false;
    }

    private async Task OnInput(ChangeEventArgs e)
    {
        _currentValue = e.Value?.ToString();
        var formattedValue = await _jsRuntime.InvokeAsync<string>("formatNumberInput", _currentValue, AllowDecimals);
        _stringValue = formattedValue;

        // 将显示格式转换为decimal可识别的格式:去掉千分位点,将小数逗号换成点
        var rawValue = formattedValue.Replace(".", "").Replace(",", ".");
        if (decimal.TryParse(rawValue, out var result))
        {
            Value = result;
            await ValueChanged.InvokeAsync(Value);
        }
    }

    private async Task OnValueChanged(ChangeEventArgs e)
    {
        await OnInput(e);
    }
}

关键修改说明

  • 按键验证逻辑:移到C#的OnKeyDown方法中,通过返回false直接阻止非法按键,避免了JS与Blazor事件对象的不兼容问题。
  • 格式化文化适配:在OnParametersSet中创建自定义CultureInfo,指定千分位为点、小数位为逗号,确保初始值显示正确。
  • JS格式化优化:统一将输入中的点替换为逗号,避免出现多个小数分隔符的问题,保证格式化后的字符串符合要求。

内容的提问来源于stack exchange,提问作者user1531040

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 19:47:02