Blazor Server自定义Select2多选控件选中值显示Null问题排查
Blazor Server中Select2多选控件无法获取选中值的问题解决
问题原因分析
- Select2覆盖原生控件事件:Select2会替换原生
<select>元素生成自定义DOM,用户的选择操作不会触发原生的@onchange事件,导致你定义的OnSelectionChanged方法从未执行。 - 类型不匹配:你的
serverID是int类型,但SelectedValues是List<string>,初始值设置时类型不兼容,叠加事件未触发的问题,最终选中值始终为Null。 - 未建立JS与Blazor的正确联动:没有监听Select2自身的
change事件来通知Blazor更新状态。
解决方案
1. 修改JS互操作代码(Select2JsInterop.js)
新增Select2的change事件监听,通过DotNet对象引用通知Blazor组件更新:
window.select2Interop = { initializeSelect2: function (elementId, dotNetRef) { $('#' + elementId).select2({ width: '100%', multiple: true }).on('change', function() { const selectedValues = $(this).val(); dotNetRef.invokeMethodAsync('OnSelect2SelectionChanged', selectedValues); }); }, getSelectedValues: function (elementId) { return $('#' + elementId).val(); }, setSelectedValues: function (elementId, values) { $('#' + elementId).val(values).trigger('change'); } };
2. 重构自定义Select2组件(Select2MultiSelect.razor)
移除原生@onchange,改用JS触发的回调,同时处理类型转换与组件生命周期:
<select id="@ElementId"> @foreach (var option in Options) { <option value="@option.serverID.ToString()">@option.server_Name</option> } </select> @code { [Inject] private IJSRuntime JSRuntime { get; set; } private DotNetObjectReference<Select2MultiSelect>? _dotNetRef; [Parameter] public string ElementId { get; set; } = "select2_" + Guid.NewGuid().ToString("N"); [Parameter] public List<SelectedServers> Options { get; set; } = new(); [Parameter] public List<string> SelectedValues { get; set; } = new(); [Parameter] public EventCallback<List<string>> SelectedValuesChanged { get; set; } protected override void OnInitialized() { _dotNetRef = DotNetObjectReference.Create(this); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { await JSRuntime.InvokeVoidAsync("select2Interop.initializeSelect2", ElementId, _dotNetRef); var stringValues = SelectedValues ?? new List<string>(); await JSRuntime.InvokeVoidAsync("select2Interop.setSelectedValues", ElementId, stringValues); } } [JSInvokable] public async Task OnSelect2SelectionChanged(List<string> values) { SelectedValues = values ?? new List<string>(); await SelectedValuesChanged.InvokeAsync(SelectedValues); StateHasChanged(); } public void Dispose() { _dotNetRef?.Dispose(); } public class SelectedServers { public int serverID { get; set; } public string server_Name { get; set; } = string.Empty; } }
3. 调整UI使用代码
初始化选中值为非空列表,确保UI能正确刷新:
<Select2MultiSelect Options="@SimilarServers" SelectedValues="@selectedValues" SelectedValuesChanged="@OnSelectedValuesChanged" /> <p>Selected values: @string.Join(", ", selectedValues)</p> @code { private List<string> selectedValues = new(); private async Task OnSelectedValuesChanged(List<string> newSelectedValues) { selectedValues = newSelectedValues; StateHasChanged(); } private List<Select2MultiSelect.SelectedServers> SimilarServers = new() { new Select2MultiSelect.SelectedServers { serverID = 1, server_Name = "atapa222" }, new Select2MultiSelect.SelectedServers { serverID = 2, server_Name = "linuxdata2" } }; }
4. 修正JS引用顺序(_Host.cshtml)
确保依赖库加载顺序正确:
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> <script src="~/assets/js/select2jsinterop.js"></script> <script src="_framework/blazor.server.js"></script>
关键注意点
- 必须监听Select2自身的
change事件,而非原生select的事件 - 确保
option的value类型与SelectedValues一致(此处将int转为string) - JS触发Blazor回调后,需要手动调用
StateHasChanged()触发UI更新
内容的提问来源于stack exchange,提问作者ahmed abdelaziz
相关产品推荐
相关产品推荐

