Bootstrap Blazor官方目前只提供单个Select选择器,如果要想实现下图所示的多个Select选择器联合选择,则需要通过编写自定义组件来实现。
主要通过Bootstrap的data-bs-toggle属性来实现展开和折叠效果。
.razor文件内容如下:
@typeparam TValue
@inherits SelectBase<TValue><div class="d-flex dropdown-select">@if (DItems is not null && DItems.Count > 0){@foreach (var dItem in DItems){@if (dItem.SItems != null && dItem.SItems.Count > 0){<div class="dropdown"><button class="@($"btn {(dItem.SItems.Where(t => t.Active).Count() > 0 ? "btn-primary" : "")} dropdown-toggle")" type="button" data-bs-toggle="dropdown" aria-expanded="false">@dItem.ParentItem.Text</button><ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">@foreach (var item in dItem.SItems){<li><label class="d-flex align-items-center"><input type="checkbox" @bind="@item.Active" @onclick="async() => { item.Active = !item.Active; await OnClink(dItem.ParentItem, item);}" />@item.Text</label></li>}</ul></div>}else{<div class="dropdown"><button class="@($"btn {(dItem.ParentItem.Active ? "btn-primary" : "")}")" type="button" @onclick="async () => { dItem.ParentItem.Active = !dItem.ParentItem.Active; await OnClink(dItem.ParentItem, null); }">@dItem.ParentItem.Text</button></div>}}}
</div>
.razor.cs内容如下:
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using System.Collections;
using System.Diagnostics.CodeAnalysis;namespace BlazorServerApp.Components.BsBlzExtends
{/// <summary>/// DropdownSelect组件/// </summary>/// <typeparam name="TValue">目前只支持string类型</typeparam>public partial class DropdownSelect<TValue>{[NotNull][Parameter]public List<DropdownSelectedItem> DItems { get; set; }[Parameter]public Func<IEnumerable<SelectedItem>, TValue, Task>? OnSelectedChanged { get; set; }private async Task OnClink(SelectedItem parentItem, SelectedItem item) => await OnSelectStateChanged(parentItem, item, item == null ? parentItem.Active : item.Active);private async Task OnSelectStateChanged(SelectedItem parentItem, SelectedItem item, bool v){try{var dItem = DItems.FirstOrDefault(d => d.ParentItem.Text == parentItem.Text);if (item != null){if (item.Text.Equals("全部") && v){dItem.SItems.ForEach(d => { d.Active = true; });}else if (item.Text.Equals("全部") && !v){dItem.SItems.ForEach(d => { d.Active = false; });}if (dItem.SItems.Where(d => d.Active == false && d.Text.Equals("全部") == false).Count() > 0){var all = dItem.SItems.FirstOrDefault(d => d.Text.Equals("全部"));all.Active = false;}else if (dItem.SItems.Where(d => d.Active == false && d.Text.Equals("全部") == false).Count() <= 0){var all = dItem.SItems.FirstOrDefault(d => d.Text.Equals("全部"));all.Active = true;}}if (ValueType == typeof(string)){var values = DItems.Select(d => {if ((d.SItems == null || d.SItems.Count <= 0)){if (d.ParentItem.Active){return d.ParentItem.Value;}else{return null;}}var vs = d.SItems.Where(t => t.Active && !string.IsNullOrEmpty(t.Value)).Select(t => t.Value).ToList();if (vs != null){var temp = string.Join(",", vs);return temp;}else{return null;}}).ToList();CurrentValueAsString = string.Join(",", values.Where(d => !string.IsNullOrEmpty(d)));}else if (ValueType.IsGenericType){var t = ValueType.GenericTypeArguments;if (Activator.CreateInstance(typeof(List<>).MakeGenericType(t)) is IList instance){foreach (var sl in dItem.SItems.Where(i => i.Active)){if (sl.Value.TryConvertTo(t[0], out var val)){instance.Add(val);}}CurrentValue = (TValue)instance;}}if (OnSelectedChanged != null){await OnSelectedChanged.Invoke(dItem.SItems, Value);}}catch{throw;}}}public class DropdownSelectedItem{[NotNull]public SelectedItem ParentItem { get; set; }public new List<SelectedItem> SItems { get; set; }}
}
.razor.css内容如下:
.dropdown-select {flex-wrap: wrap;
}.dropdown{margin-right: 0.1rem;
}input {margin-left: 0.3rem;margin-right: 0.3rem;
}