Blazor中绑定@bind的HTML time输入控件输完小时后自动失焦问题
问题成因
- 原生HTML time输入框的内置交互逻辑为:用户输入完小时段的合法值后,会自动将输入选中段切换到分钟/秒段,这个过程仅触发
input事件,不会触发change事件,也不会主动失焦。 - Blazor默认的
@bind对time类型输入框会自动绑定oninput事件同步值到绑定属性:用户输完小时触发input事件时,Timer.Time属性会立即更新,进而触发组件重渲染。 - 重渲染过程中Blazor会把绑定的新值重新同步回DOM的input元素,这个操作会打断time输入框原本的内置选中段切换逻辑,直接导致输入焦点丢失。
- 移除
@bind后,输入过程中没有属性更新、组件重渲染的流程,不会打断原生交互,因此功能完全正常。
解决方案
方案1:仅需输入完成后同步值(绝大多数场景适用)
直接显式指定@bind的触发事件为onchange,只有用户完全输入完、触发失焦的change事件时才会同步值、触发重渲染,输入过程中不会打断原生交互:
<input type="time" class="form-control" step="300" @onblur="@(async () => await Update())" @bind="Timer.Time" @bind:event="onchange" />
如果要避免@onblur和onchange事件重复触发逻辑,可以把原有@onblur的逻辑替换为@bind:after,保证绑定值更新完成后再执行后续操作:
<input type="time" class="form-control" step="300" @bind="Timer.Time" @bind:event="onchange" @bind:after="@Update" />
方案2:需要输入过程中实时同步绑定值
如果业务需要输入过程中就拿到最新的时间值(比如实时校验、联动其他组件),可以移除默认@bind,改用手动绑定的方式,避免重渲染时覆盖DOM的value打断原生交互:
如果Timer.Time是字符串类型,直接用以下写法:
<input type="time" class="form-control" step="300" value="@Timer.Time" @onblur="@(async () => await Update())" @oninput="@(e => Timer.Time = e.Value?.ToString())" />
如果Timer.Time是TimeSpan?或DateTime?这类时间类型,需要在input事件中做格式转换:
<input type="time" class="form-control" step="300" value="@Timer.Time?.ToString(@"hh\:mm")" @onblur="@(async () => await Update())" @oninput="@(e => { if (TimeSpan.TryParse(e.Value?.ToString(), out var parsedTime)) { Timer.Time = parsedTime; } })" />
注意:如果绑定的是TimeSpan/DateTime类型,需确保绑定到
value的格式符合time输入框的要求,比如格式化为HH:mm格式,避免格式不匹配导致输入值无法正确回显。
这种写法下,输入过程中Timer.Time会实时更新,但Blazor重渲染时会检测到DOM的value已经和绑定值一致,不会主动修改DOM的value属性,因此不会打断原生的选中段切换逻辑。
内容的提问来源于stack exchange,提问作者Jyina
相关产品推荐
相关产品推荐

