使用 Ctrl +V 组合键时,是否可以更新附加到 Blazor 中输入文本项的绑定变量?

Is there a way to update a binding variable attached to an Input text Item in Blazor when using Ctrl +V combination keys?

我有这个输入,用于捕获 phone 号码。 当用户输入一个数字并按下 "Enter" 键时,触发方法 "KeyWasPressed" 并进行一些验证。这按预期工作但是...

例如,当用户从 excel 复制并粘贴数字时,变量 @Phone 不会更新其值,因此当用户按下 "Enter" 验证发送的键和空值。

有没有办法在将一些文本粘贴到输入控件时 refresh/update @Phone 变量?

这是我的代码片段:

<input type="number" class="form-control" @bind="@Phone" @onkeypress="@(async e => await KeyWasPressed(e))" placeholder="Client Phone Number" />

@code {

    string Phone { get; set; }

    private async Task GetClientInfo()
    {
        if(String.IsNullOrWhiteSpace(Phone))
        {
            notificationMessages = $"Add a phone number";
        }
        else
        {
            showSpinner = true;

            clientInfo = await ApiHelper.GetClientInfoByPhone(Phone);           

            if(clientInfo != null)
            {
                var singleViewId = clientInfo?.SingleViewId;
                var customerNumber = clientInfo?.Accounts?.FirstOrDefault().CustomerNumber;
                var status = clientInfo?.Accounts?.FirstOrDefault().Status;
                showClientInformation = true;

                var CrossSell = clientInfo?.Accounts[0]?.CrossSell;


            }
            else
            {
                showClientInformation = false;
                notificationMessages = $"No client data for this phone ({Phone})";
            }

            showSpinner = false;
        }
    }

    private async Task KeyWasPressed(KeyboardEventArgs args)
    {
        if(args.Key == "Enter")
        {
            //await GetClientInfo();
        }
    }
}

原因

我可以重现同样的问题。原来是因为当我们copy sth & paste到input里,然后按下Enter键,enter键事件在之前被触发change事件。

查看事件顺序:

因为Enter KeyPress事件在change事件之前触发,所以Phone属性还没有更新

如何修复

一种可能的解决方法是监听粘贴事件。但不幸的是,目前在使用 Blaozr 的原生 onpaste 时存在限制(参见 https://github.com/aspnet/AspNetCore/issues/14133#issuecomment-533198522)。

既然团队成员建议我们应该使用jsinterop,我们可以添加一个interHelper.handlePaste功能:

<script>
    var interHelper={
        handlePaste: function (){
            var node = document.getElementById('phoneInput');
            return node.value;
        },
    }
</script>
<script src="_framework/blazor.server.js"></script>

然后粘贴时手动刷新最新值:

<input id='phoneInput' type="number" class="form-control" @bind="@Phone" 
    @onpaste="HandlePaste"
    @onkeypress="@(async e => await KeyWasPressed(e))" 
    placeholder="Client Phone Number" />

@code {
    ...

    private async Task HandlePaste(ClipboardEventArgs e){
        var str = await jsRuntime.InvokeAsync<string>("interHelper.handlePaste");
        this.Phone= str;
    }
}

演示

复制“107783”并粘贴到输入中并按 Enter 键:

直接解:

只需使用@bind-value="@Phone" @bind-value:event="oninput":


<input type="number" @bind-value="@Phone" @bind-value:event="oninput" 
       @onkeyup="@OnUserFinish"/>
<p>@clientInfo</p>

@code {
    protected string Phone { get; set; } 
    protected string clientInfo {get; set;}

    private async Task OnUserFinish(KeyboardEventArgs e)
    {
        if (e.Key == "Enter")
          clientInfo = await Fake_ApiHelper_GetClientInfoByPhone(Phone);      
    }

    private async Task<string> Fake_ApiHelper_GetClientInfoByPhone(string phone)
    {
        await Task.CompletedTask;
        return $"Client phone: {phone}";
    }
}

奖励曲目:

移动到用户友好的去抖动版本:

@using System.Timers;

<input type="number" @bind-value="@Phone" @bind-value:event="oninput" 
       @onkeyup="@HandleKeyUp"/>
<p>@clientInfo</p>

@code {
    protected string Phone { get; set; } 
    protected string clientInfo {get; set;}
    private System.Timers.Timer aTimer;

    protected override void OnInitialized()
    {
        aTimer = new System.Timers.Timer(250);
        aTimer.Elapsed += OnUserFinish;
        aTimer.AutoReset = false;
    }

    void HandleKeyUp(KeyboardEventArgs e)
    {
        // remove previous one
        aTimer.Stop();

        // new timer
        aTimer.Start();        
    }    

    private void OnUserFinish(Object source, ElapsedEventArgs e)
    {
        InvokeAsync( async () =>
          {
            clientInfo = await Fake_ApiHelper_GetClientInfoByPhone(Phone);      
            StateHasChanged();
          });
    }

    private async Task<string> Fake_ApiHelper_GetClientInfoByPhone(string phone)
    {
        await Task.CompletedTask;
        return $"Client phone: {phone}";
    }
}