如何编写Blazor自定义组件实现按键过滤?解决InputNumber Firefox兼容问题
自定义Blazor输入组件实现通用字符过滤(解决Firefox下InputNumber失效问题)
问题背景
Blazor自带的InputNumber组件会渲染<input type="number">,但这个原生输入框在Firefox里不会限制非数字输入。我尝试写了一个自定义过滤组件,虽然<p>标签能正确显示过滤后的数值,但输入框本身还是会显示所有按下的字符,怎么解决这个问题?要求方法支持任意字符过滤,不只是数字。
我的尝试代码:
@inherits InputNumber<int?> <input type="number" @bind=_value @onkeypress=OnKeypress /> <p>@_value</p> @code { private string _value; private void OnKeypress(KeyboardEventArgs e) { if (Regex.IsMatch(e.Key, "[0-9]")) _value += e.Key; } }
解决方案
你之前的问题出在@bind和手动按键处理的冲突:@bind会自动同步输入框的原生值和你的_value变量,导致你过滤后的_value和输入框实际显示的值不一致。要解决这个问题,需要阻止不符合规则的按键默认行为,同时自己控制输入框的显示值,还要和InputNumber的Value保持同步。
1. 通用过滤组件实现
下面是一个支持自定义过滤规则的组件,不仅能处理数字,还能适配任意字符过滤需求:
@inherits InputNumber<TValue> @using System.Globalization <input type="text" value="@_displayValue" @oninput="OnInput" @onkeydown="OnKeyDown" /> @code { private string _displayValue; // 自定义过滤规则参数,外部传入判断逻辑 [Parameter] public Func<string, bool> CharacterFilter { get; set; } = _ => true; protected override void OnInitialized() { // 初始化时同步Value到显示值 _displayValue = CurrentValueAsString; base.OnInitialized(); } protected override void OnParametersSet() { // 当外部Value变化时更新显示值 if (!EqualityComparer<TValue>.Default.Equals(CurrentValue, ParseValueFromString(_displayValue))) { _displayValue = CurrentValueAsString; } base.OnParametersSet(); } private void OnInput(ChangeEventArgs e) { var inputValue = e.Value?.ToString() ?? string.Empty; // 应用过滤规则,保留符合要求的字符 var filteredValue = new string(inputValue.Where(c => CharacterFilter(c.ToString())).ToArray()); // 同步到组件的Value if (TryParseValueFromString(filteredValue, out var parsedValue, out var validationErrorMessage)) { CurrentValue = parsedValue; _displayValue = filteredValue; } else { // 解析失败时回显过滤后的值,同时保留验证逻辑 _displayValue = filteredValue; } } private void OnKeyDown(KeyboardEventArgs e) { // 允许控制键(比如退格、删除、方向键) var isControlKey = e.Key is "Backspace" or "Delete" or "ArrowLeft" or "ArrowRight" or "Tab"; if (isControlKey) return; // 如果输入的字符不符合过滤规则,阻止默认行为 if (!CharacterFilter(e.Key)) { e.PreventDefault(); } } }
2. 使用示例(数字过滤)
在页面中引用这个组件,传入数字过滤规则:
<CustomFilterInputNumber TValue="int?" @bind-Value="@MyNumber" CharacterFilter="@(c => Regex.IsMatch(c, "[0-9]"))" /> @code { private int? MyNumber; }
关键要点说明
- 改用
type="text"替代type="number":原生number输入框在不同浏览器行为不一致,用文本输入框能完全控制输入内容 - 双层面过滤:
OnKeyDown阻止不符合规则的按键输入,OnInput处理粘贴等非按键输入场景(比如右键粘贴),确保所有输入都被过滤 - 可自定义过滤规则:通过
CharacterFilter参数传入任意判断逻辑,比如只允许字母、特定符号等 - 保留
InputNumber的原有功能:继承自InputNumber,所以自带验证、双向绑定等特性,不需要重新实现
内容的提问来源于stack exchange,提问作者lonix
相关产品推荐
相关产品推荐

