Blazor中无需修改组件状态触发重渲染以撤销无效用户输入的方法?
问题根因
Blazor的虚拟DOM差分逻辑会在渲染时对比新旧虚拟节点的属性差异,当调用StateHasChanged时,如果检测到input的value绑定的count值和上一次渲染时完全一致,就会跳过更新真实DOM的输入框值,因此用户输入的无效内容会保留在界面上。
以下是三种不需要依赖bind-xxx能力的可行方案,可适配任意自定义输入校验规则:
方案1:用@key特性强制重建输入元素
这是最符合Blazor声明式开发习惯的方案,不需要JS互操作。给输入框绑定一个唯一key,每次遇到无效输入时更新key,Blazor会销毁旧的input元素,重新渲染一个全新的input,值自然就会同步为当前的count值。
完整代码示例:
<label>Count:</label> <button @onclick=Increment>@count times!</button><br> A: <input @oninput=OnChange value="@count" @key="_renderKey"><br> B: <input @bind-value=count @bind-value:event="oninput"> @code { int count = 1; // 用于强制重建input的key计数器 private int _renderKey = 0; void Increment() => count++; void OnChange(ChangeEventArgs e) { var userValue = e.Value?.ToString(); if (int.TryParse(userValue, out var v)) { count = v; } else { if (String.IsNullOrWhiteSpace(userValue)) { count = 0; } else { // 输入无效,更新key强制重渲染input _renderKey++; } } } }
方案2:用JS互操作直接更新输入框值
如果不想重建元素影响性能,可以直接调用JS操作真实DOM修改输入框值,不需要触发组件重渲染:
@inject IJSRuntime JS <label>Count:</label> <button @onclick=Increment>@count times!</button><br> A: <input @oninput=OnChange value="@count" @ref="_inputRef"><br> B: <input @bind-value=count @bind-value:event="oninput"> @code { int count = 1; private ElementReference _inputRef; void Increment() => count++; async Task OnChange(ChangeEventArgs e) { var userValue = e.Value?.ToString(); bool isValid = true; if (int.TryParse(userValue, out var v)) { count = v; } else { isValid = false; if (String.IsNullOrWhiteSpace(userValue)) { count = 0; } } if (!isValid) { // 直接调用JS修改输入框值 await JS.InvokeVoidAsync("el => el.value = $0", _inputRef, count.ToString()); } } }
方案3:临时修改状态触发重渲染(Hack方案)
你也可以先把count临时修改为一个不会用到的中间值,触发渲染后再改回原值,两次StateHasChanged调用就能让输入框值同步:
void OnChange(ChangeEventArgs e) { var userValue = e.Value?.ToString(); var originalCount = count; bool needForceRender = false; if (int.TryParse(userValue, out var v)) { count = v; } else { if (String.IsNullOrWhiteSpace(userValue)) { count = 0; } else { needForceRender = true; } } if (needForceRender) { // 临时改值触发渲染 count = int.MinValue; StateHasChanged(); // 改回原值再次渲染 count = originalCount; StateHasChanged(); } }
内容的提问来源于stack exchange,提问作者noseratio
相关产品推荐
相关产品推荐

