首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用于过滤击键的Blazor组件

用于过滤击键的Blazor组件
EN

Stack Overflow用户
提问于 2022-10-25 13:45:35
回答 4查看 116关注 0票数 2

Blazor具有将输入限制为数字的InputNumber组件。然而,这会呈现一个火狐不尊重的<input type=number .../> (它允许任何文本)。

因此,我尝试创建一个自定义组件来过滤输入:

代码语言:javascript
运行
复制
@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;
  }
}

<p>显示正确的值。但输入本身显示所有按键。

如何编写自定义组件来筛选击键?(在本例中,我正在筛选数字,但我假设同样的方法也适用于过滤任何字符。)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2022-10-26 18:07:19

如果您想使用Blazor EditForm基础结构,可以创建一个自定义InputNumber

下面的代码继承自InputNumber,并进行以下更改。我已经用Firefox和Edge进行了测试,但我的笔记本电脑上没有安装Chrome。

  1. 输入类型被更改为text。这确保了所有浏览器的一致行为--如果设置为‘`number,则不是这样。
  2. input value映射到一个新的内部字段,该字段将从一个新的
  3. 升级到SetValue,以捕获每个keypress.
  4. SetValue包含检查有效数字输入的新逻辑。代码有内联评论。

代码语言:javascript
运行
复制
@inherits InputNumber<TValue>
@typeparam TValue

<input type="text"
       value="@this.displayValue"
       class="@this.CssClass"
       @oninput=SetValue
       @attributes=this.AdditionalAttributes
       @ref=this.Element />

@code {
    // create a unique string based on the null Ascii char
    //private static string emptyString = ((char)0).ToString();
    private static string emptyString = string.Empty;
    private string? displayValue;

    public async Task SetValue(ChangeEventArgs e)
    {
        // Get the current typed value
        var value = e.Value?.ToString();

        // Check if it's a number of the TValue or null
        var isValidNumber = BindConverter.TryConvertTo<TValue>(value, System.Globalization.CultureInfo.CurrentCulture, out var num)
            || value is null;

         // If it's not valid we need to reset the value
        if (!isValidNumber)
        {
            // Set the value to an empty string
            displayValue = emptyString;
            // Call state has changed to render the component
            StateHasChanged();
            // Give thw renderer some processor time to execute the queued render by creating a Task continuation
            await Task.Delay(1);
            // Set the display to the previous value stored in CurrentValue 
            displayValue = FormatValueAsString(CurrentValue);
            // done
            return;
        }

        // We have a numbr so set the two fields to the current value
        // This is the display value
        displayValue = value;
        // This triggers the full InputBase/EditContext logic
        CurrentValueAsString = value;
    }
}

为什么我们需要双重渲染技巧

如果无效的数字要修复实际DOM和呈现的DOM之间的不一致,我们必须加倍呈现。

考虑到这一点:

当前值为12。渲染器的DOM段是value="12".

  • We,将输入更改为12q.

  • The浏览器DOM现在是value="12q",而渲染器DOM仍然是value="12"

如果我们现在将Renderer设置为value="12",那么它没有改变。Diffing引擎看不到差别,也不更新浏览器UI。

为了解决这个问题,我们必须在将Renderer的DOM设置为原始值之前确保它被设置为其他东西。我们将其设置为空字符串,给渲染器一些处理器时间,让它实际呈现组件,然后将其设置为原来的设置。

票数 2
EN

Stack Overflow用户

发布于 2022-10-25 16:35:14

你可以试试这个:

代码语言:javascript
运行
复制
@using Microsoft.AspNetCore.Components

<input type="number" value=@_value @oninput=OnInput />
<p>@_value</p>

@code {
    private int oldValue = 50;
    private int _value = 50;

    private async Task OnInput(ChangeEventArgs args) {
        int newValue;
        if(int.TryParse((string)args.Value, out newValue)){
            _value = newValue;
            oldValue = _value;
        }
        else{
            _value = 0;
            await Task.Yield();
            _value = oldValue;
        }
    }
}

诀窍是在await Task.Yield()周围的3行上,在字符错误时强制输入重行。

还请注意,此解决方案将不允许大于Int32.MaxValue或小于Int32.MinValue的数字。

编辑:

为了避免在瞬间内在输入中显示值0,我们可以强制完全输入的重建器。但是,在Mozilla中,每次写入禁止字符时,它都会失去输入的焦点。然而,它似乎保持了对Chrome的关注。

代码语言:javascript
运行
复制
@using Microsoft.AspNetCore.Components

@if(rerenderTrick){
    <input type="number" value=@_value/>
}
else{
    <input type="number" value=@_value @oninput=OnInput />
}
<p>@_value</p>

@code {
    private int _value = 50;
    private bool rerenderTrick = false;

    private async Task OnInput(ChangeEventArgs args) {
        int newValue;
        if(int.TryParse((string)args.Value, out newValue)){
            _value = newValue;
        }
        else{
            rerenderTrick = true;
            await Task.Yield();
            rerenderTrick = false;
        }
    }
}
票数 2
EN

Stack Overflow用户

发布于 2022-10-25 16:50:03

下面是一个通用的数字组件,您可以展开它,并且已经提供了一些基本功能,这些基本功能将使它看起来像一个数字输入,包括regex,以防止不允许的输入。

index.razor:

代码语言:javascript
运行
复制
@page "/"

<p>
    <label>Integer Value</label>
    <InputNumeric @bind-Value="ValueInteger" DecimalPlaces="0" />
    <span>@ValueInteger</span>
</p>

<p>
    <label>Decimal Value</label>
    <InputNumeric @bind-Value="ValueDecimal" />
    <span>@ValueDecimal</span>
</p>

@code {
    int ValueInteger = 1;
    decimal ValueDecimal = 1;
}

InputNumeric.razor

代码语言:javascript
运行
复制
@inject IJSRuntime JSRuntime
@typeparam T

<input @ref="@ElementReference"
       type="text"
       value="@ValueString"
       @onfocus="FocusEvent"
       @onblur="FormatValue"
       @oninput="ChangeEvent"
       @onchange="ChangeEvent" />

@code {

    [Parameter]
    public EventCallback<T> ValueChanged { get; set; }

    private T _value;

    [Parameter]
    public T Value
    {
        get => _value;
        set
        {
            if (EqualityComparer<T>.Default.Equals(_value, value)) return;
            _value = value;
            ValueChanged.InvokeAsync(value);
        }
    }

    [Parameter]
    public int DecimalPlaces { get; set; } = 2;

    [Parameter]
    public decimal? Step { get; set; }

    [Parameter]
    public string DisplayFormat { get; set; }

    private string ValueString { get; set; }
    private ElementReference ElementReference { get; set; }
    bool ignoreParameterSet = false;

    protected override void OnParametersSet()
    {
        if (!ignoreParameterSet)
            FormatValue();

    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
            await JSRuntime.InvokeVoidAsync("MyBlazor.SetNumericOnly", ElementReference, DecimalPlaces);
    }

    private void ChangeEvent(ChangeEventArgs e)
    {
        decimal decimalValue = CastToDecimal(e.Value);

        Value = (T)Convert.ChangeType(decimalValue, typeof(T));

        ValueChanged.InvokeAsync(Value);
    }

    private async void FocusEvent(FocusEventArgs e)
    {
        ignoreParameterSet = true;

        ValueString = Value?.ToString();

        await InvokeAsync(StateHasChanged);
    }

    private void FormatValue()
    {
        ignoreParameterSet = false;

        ValueString = String.Format(DisplayFormat ?? $"{{0:N{DecimalPlaces}}}", Value);

        StateHasChanged();
    }

    private decimal CastToDecimal(object value) {
        decimal decimalValue;

        var isDecimal = decimal.TryParse(value?.ToString(), out decimalValue);

        if (isDecimal)
        {
            decimalValue = Math.Round(decimalValue, DecimalPlaces);
        }

        return decimalValue;
    }

    private async Task OnKeyDown(KeyboardEventArgs e)
    {
        if (e.Code == "ArrowDown" || e.Code == "ArrowUp")
        {
            var step = Step ?? (DecimalPlaces > 0 ? (decimal).25 : 1);

            decimal decimalValue = CastToDecimal(Value);

            if (e.Code == "ArrowDown")
                decimalValue -= step;

            if (e.Code == "ArrowUp")
                decimalValue += step;

            Value = (T)Convert.ChangeType(decimalValue, typeof(T));

            await ValueChanged.InvokeAsync(Value);

            ValueString = Value.ToString();
        }
    }
}

Javascript:

代码语言:javascript
运行
复制
window.MyBlazor = {
    SetNumericOnly: function (element, decimalPlaces) {
        element.oninput = function (i, d) {
            return function (e) {
                var valueNegative = i.value.length > 0 ? i.value[0] == "-" : false;

                i.value = (valueNegative ? "-" : "") + i.value.replace(/[^0-9.]/g, '').replace(/(\..*?)\..*/g, '$1').replace(/^0[^.]/, '0');

                if (d === 0)
                    i.value = i.value.replace('.', '');
            }
        }(element, decimalPlaces);
    }
}

重要注意事项:

这将破坏小数分隔符不是.的区域性。你需要满足这个需求。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74195088

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档