Blazor多组件实例触发同一事件回调的问题求助
Blazor多组件实例触发同一事件回调的问题求助
各位Blazor开发者们好,我刚接触Blazor没多久,最近遇到一个奇怪的问题,想请大家帮忙排查下哪里出了问题。
我写了一个很简单的文件选择组件,包含一个只读文本框和一个自定义的“Browse”按钮(实际用隐藏的InputFile实现)。然后在页面上放了这个组件的两个实例,分别绑定了各自的回调方法Callback1和Callback2。
但现在的问题是:不管点击哪个组件的Browse按钮,最终触发的都是页面上的Callback1,完全不会触发Callback2,我实在找不到问题出在哪了😭
页面代码
@page "/" <div id="component1"> <FileSelectorComponent Title="Component1" PathChanged="Callback1"/> </div> <label for="component1">@_path1</label> <div id="component2"> <FileSelectorComponent Title="Component2" PathChanged="Callback2"/> </div> <label for="component2">@_path2</label> @code { private string? _path1; private string? _path2; protected void Callback1(IBrowserFile file) { _path1 = $"Size: {file.Size} | Name: {file.Name}"; } protected void Callback2(IBrowserFile file) { _path2 = $"Size: {file.Size} | Name: {file.Name}"; } }
组件代码
<input type="text" class="form-control" id="pathText" readonly="readonly" value="@_path" placeholder="Select file..." /> <button class="btn btn-outline-secondary" id="openDialog"> <label for="file">Browse</label> </button> <InputFile id="file" accept=".csv" OnChange="UpdatePath" hidden /> @code { [Parameter] [EditorRequired] public string Title { get; set; } = "FileSelectorComponent"; [Parameter] public EventCallback<IBrowserFile> PathChanged { get; set; } private string? _path; private async Task UpdatePath(InputFileChangeEventArgs e) { _path = e.File.Name; await PathChanged.InvokeAsync(e.File); } }
问题原因分析
其实问题出在HTML元素的id唯一性上!
你的组件里给多个元素设置了固定的id(比如pathText、openDialog、file),当页面上渲染两个组件实例时,页面上会存在两个id为file的InputFile元素,两个id为pathText的输入框,以此类推。而HTML规范要求页面上的id必须是全局唯一的,当你点击第二个组件的Browse按钮时,<label for="file">会在页面上找到第一个id为file的元素(也就是第一个组件的InputFile),自然就触发了第一个组件的回调方法Callback1。
解决方案
给每个组件实例生成唯一的id,确保页面上所有元素的id不重复。可以通过在组件内部生成一个唯一标识来实现:
修改后的组件代码如下:
<input type="text" class="form-control" id="pathText-@_uniqueId" readonly="readonly" value="@_path" placeholder="Select file..." /> <button class="btn btn-outline-secondary" id="openDialog-@_uniqueId"> <label for="file-@_uniqueId">Browse</label> </button> <InputFile id="file-@_uniqueId" accept=".csv" OnChange="UpdatePath" hidden /> @code { [Parameter] [EditorRequired] public string Title { get; set; } = "FileSelectorComponent"; [Parameter] public EventCallback<IBrowserFile> PathChanged { get; set; } private string? _path; private string _uniqueId; protected override void OnInitialized() { // 生成唯一标识 _uniqueId = Guid.NewGuid().ToString("N"); } private async Task UpdatePath(InputFileChangeEventArgs e) { _path = e.File.Name; await PathChanged.InvokeAsync(e.File); } }
这样每个组件实例的元素id都会带上唯一的后缀,浏览器就能正确匹配每个组件的Browse按钮和对应的InputFile,两个组件的回调也就会各自触发啦!
备注:内容来源于stack exchange,提问作者grmihel
相关产品推荐
相关产品推荐

