C# Blazor文本字段Oninput用户键入延迟

C# Blazor文本字段Oninput用户键入延迟,c#,throttling,blazor,blazor-server-side,debounce,C#,Throttling,Blazor,Blazor Server Side,Debounce,如何在Blazor中为事件(OnInput)添加延迟?例如,如果用户正在文本字段中键入内容,您希望等待用户完成键入。 Blazor.Templates::3.0.0-preview8.19405.7 代码: @page "/" <input type="text" @bind="Data" @oninput="OnInputHandler"/> <p>@Data</p> @code { public string Data { get; se

如何在Blazor中为事件(OnInput)添加延迟?
例如,如果用户正在文本字段中键入内容,您希望等待用户完成键入。

Blazor.Templates::3.0.0-preview8.19405.7

代码:

@page "/"
<input type="text" @bind="Data" @oninput="OnInputHandler"/>
<p>@Data</p>

@code {    
    public string Data { get; set; }   

    public void OnInputHandler(UIChangeEventArgs e)
    {
        Data = e.Value.ToString();
    }    
}
@page/“
@资料

@代码{ 公共字符串数据{get;set;} InpAuthHandler上的公共无效(UIChangeEventArgs e) { Data=e.Value.ToString(); } }
解决方案: 你的问题没有单一的解决办法。下面的代码只是一种方法。看一看,并根据您的要求进行调整。代码在每个
键控
上重置计时器,只有最后一个计时器引发
OnUserFinish
事件。 记住通过实现
IDisposable

@using System.Timers;
@implements IDisposable;
...
<input type="text" @bind-value="Data" @bind-value:event="oninput" 
       @onkeyup="@HandleKeyUp"/>
<p>@Data2</p>

@code {
    public string Data { get; set; }   
    public string Data2 { get; set; }  
    private Timer aTimer;

    protected override void OnInitialized()
    {
        aTimer = new Timer(1000);
        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( () =>
          {
            Data2 = $"User has finished: {Data}";
            StateHasChanged();
          });
    }
    void IDisposable.Dispose()
    {
        aTimer?.Dispose();
    }
}
@使用系统计时器;
@实现可识别性;
...
@数据2

@代码{ 公共字符串数据{get;set;} 公共字符串Data2{get;set;} 私人定时器; 受保护的覆盖无效OnInitialized() { aTimer=新定时器(1000); aTimer.appeased+=OnUserFinish; aTimer.AutoReset=false; } 无效HandleKeyUp(键盘事件参数e) { //删除上一个 停止(); //新定时器 aTimer.Start(); } 私有void OnUserFinish(对象源,ElapsedEventArgs e) { InvokeAsync(()=> { Data2=$“用户已完成:{Data}”; StateHasChanged(); }); } void IDisposable.Dispose()无效 { aTimer?.Dispose(); } }
用例: 这段代码的用例的一个例子是避免后端请求,因为在用户停止键入之前不会发送请求

运行: 我已经创建了一组。其中之一是具有多种输入类型和更多功能。Blazor.Components.Debounce.Input在上提供

你可以试试这个


注意:目前正在预览中。最终版本将随.NET5一起发布。发布

此答案介于之前的答案之间,即介于和之间

它利用了强大的库(又称Rx),我认为这是在正常情况下解决此类问题的唯一合理方法

解决方案 安装NuGet软件包后,您可以在组件中导入所需的名称空间:

@使用System.Reactive.Subjects
@使用System.Reactive.Linq
在组件上创建一个
Subject
字段,作为输入事件和可观察管道之间的粘合剂:

@code{
私有主题searchTerm=new();
// ...
}
主题
与您的
输入连接起来


最后,定义可观察的
管道:

@code{
// ...
私人物品[]?物品;
受保护的重写异步任务OnInitializedAsync(){
搜索词
.节气门(时间跨度从毫秒(200))
.选择(e=>(字符串?)e.Value)
.Select(v=>v?.Trim())
.DistinctUntilChanged()
.SelectMany(搜索内容)
.订阅(ts=>{
事物=ts;
StateHasChanged();
});
}
私有任务SearchThings(字符串?searchTerm=null)
=>HttpClient.GetFromJsonAsync($“api/things?search={searchTerm}”)
}
上面的示例管道将

  • 给用户200毫秒的时间完成输入(也称为取消抖动或限制输入)
  • ChangeEventArgs
    中选择键入的值
  • 修剪它
  • 跳过与上一个相同的任何值
  • 使用到目前为止的所有值发出HTTP GET请求
  • 将响应数据存储在字段
    things
  • 最后告诉组件它需要重新渲染
如果您的标记中有如下内容,则在键入时将看到它被更新:

@foreach(事物中的var thing){
}
附加说明 别忘了打扫卫生 您应该像这样正确地处理事件订阅:

@实现组件顶部的IDisposable//
//加价
@代码{
// ...
私人IDisposable?订阅;
public void Dispose()=>订阅?.Dispose();
受保护的重写异步任务OnInitializedAsync(){
订阅=搜索期限
.节气门(时间跨度从毫秒(200))
// ...
.认购(/*…*/);
}
}
Subscribe()
实际上返回一个
IDisposable
,您应该将其与组件一起存储和处置。但不要在其上使用
using
,因为这会过早地破坏订阅

开放性问题 有些事情我还没有弄明白:

  • 是否可以避免调用
    statehaschange()
  • 是否可以避免调用
    Subscribe()
    ,并直接绑定到标记内部的
    可观察的
    ,就像使用
  • 是否可以避免创建
    主题
    ?Rx支持从C#
    事件
    s创建
    可观察的
    s,但是如何获取
    oninput
    事件的C对象

您好,感谢您的回答和解决方案!这正是我想要的,我想我必须添加Javascript:P作为提示,当您使用System.Timers添加
@时,此源代码可以工作确保在的dispose方法上处置计时器component@Alexandre哇,谢谢你的建议。你真的很乐意改进答案吗?可以自由编辑。只需查看一下debounce和Throttling,我就发现了:有机会获得.NET Core 3.1版本吗?@akrobet谢谢联系我。我正在使用新的CSS隔离和JS互操作特性。因此,这已经是巨大的努力,以w