Skip to content

Commit 9f1df2b

Browse files
authored
feat(MultiSelect): redesign IsFixedSearch function (#5651)
* refactor: IsFixedSearch 移动到基类 * doc: 代码规范化 * fix: 重构固定搜索栏功能 * doc: 更新示例 * test: 更新单元测试 * refactor: 移动 DropdownMenuClassString 到基类 * refactor: 改造 SelectGeneric 组件适配 IsFixedSearch 功能 * test: 更新单元测试 * refactor: 精简代码 * doc: 更新示例
1 parent 3a7ffe4 commit 9f1df2b

File tree

12 files changed

+140
-112
lines changed

12 files changed

+140
-112
lines changed

src/BootstrapBlazor.Server/Components/Samples/MultiSelects.razor

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,35 @@ private enum MultiSelectEnumFoo
114114
</DemoBlock>
115115

116116
<DemoBlock Title="@Localizer["MultiSelectSearchTitle"]" Introduction="@Localizer["MultiSelectSearchIntro"]" Name="Search">
117-
<section ignore>@((MarkupString)Localizer["MultiSelectSearchDescription"].Value)</section>
118-
<MultiSelect Items="@Items" @bind-Value="@SelectedSearchItemsValue" ShowSearch="true" OnSearchTextChanged="@OnSearch"></MultiSelect>
119-
<section ignore>@SelectedSearchItemsValue</section>
120-
<ConsoleLogger @ref="Logger"></ConsoleLogger>
117+
<section ignore>
118+
<p>@((MarkupString)Localizer["MultiSelectSearchDescription"].Value)</p>
119+
<div class="row g-3">
120+
<div class="col-12 col-sm-6">
121+
<BootstrapInputGroup>
122+
<BootstrapInputGroupLabel DisplayText="IsFixedSearch" />
123+
<Checkbox @bind-Value="@_isFixedSearch" />
124+
</BootstrapInputGroup>
125+
</div>
126+
</div>
127+
</section>
128+
129+
<div class="row g-3">
130+
<div class="col-12 col-sm-6">
131+
<MultiSelect Items="@Items" @bind-Value="@SelectedSearchItemsValue"
132+
ShowSearch="true" IsFixedSearch="_isFixedSearch" OnSearchTextChanged="@OnSearch">
133+
</MultiSelect>
134+
</div>
135+
<div class="col-12 col-sm-6">
136+
<MultiSelect Items="@LongItems" @bind-Value="@SelectedMaxItemsValue"
137+
ShowSearch="true" IsFixedSearch="_isFixedSearch">
138+
</MultiSelect>
139+
</div>
140+
</div>
141+
142+
<section ignore>
143+
<p>@SelectedSearchItemsValue</p>
144+
<ConsoleLogger @ref="Logger"></ConsoleLogger>
145+
</section>
121146
</DemoBlock>
122147

123148
<DemoBlock Title="@Localizer["MultiSelectGroupTitle"]" Introduction="@Localizer["MultiSelectGroupIntro"]" Name="Group">

src/BootstrapBlazor.Server/Components/Samples/MultiSelects.razor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ private enum MultiSelectEnumFoo
108108

109109
private string? _editString;
110110

111+
private bool _isFixedSearch;
112+
111113
private async Task<SelectedItem> OnEditCallback(string value)
112114
{
113115
await Task.Delay(100);

src/BootstrapBlazor.Server/Components/Samples/Selects.razor

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,14 @@
333333
</section>
334334
<div class="row g-3">
335335
<div class="col-12 col-sm-6">
336-
<Select TValue="string" Items="Items" ShowSearch="true" IsClearable="_isShowSearchClearable" IsFixedSearch="_isFixedSearch" />
336+
<Select TValue="string" Items="Items" ShowSearch="true"
337+
IsClearable="_isShowSearchClearable" IsFixedSearch="_isFixedSearch">
338+
</Select>
337339
</div>
338340
<div class="col-12 col-sm-6">
339-
<Select TValue="string" Items="StringItems" ShowSearch="true" IsClearable="_isShowSearchClearable" IsFixedSearch="_isFixedSearch" />
341+
<Select TValue="string" Items="StringItems" ShowSearch="true"
342+
IsClearable="_isShowSearchClearable" IsFixedSearch="_isFixedSearch">
343+
</Select>
340344
</div>
341345
</div>
342346
</DemoBlock>

src/BootstrapBlazor/Components/Select/MultiSelect.razor

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -48,63 +48,71 @@
4848
<span class="@AppendClassString"><i class="@DropdownIcon"></i></span>
4949
}
5050
</div>
51-
<div class="dropdown-menu">
52-
<div class="@SearchClassString">
53-
<input type="text" class="form-control search-text" autocomplete="off" value="@SearchText" aria-label="search" />
54-
<i class="@SearchIconString"></i>
55-
<i class="@SearchLoadingIconString"></i>
56-
</div>
57-
@if (ShowToolbar)
51+
<div class="@DropdownMenuClassString">
52+
@if (ShowSearch)
5853
{
59-
<div class="toolbar">
60-
@if (ShowDefaultButtons)
61-
{
62-
<DynamicElement TagName="button" type="button" class="btn" OnClick="SelectAll">@SelectAllText</DynamicElement>
63-
<DynamicElement TagName="button" type="button" class="btn" OnClick="InvertSelect">@ReverseSelectText</DynamicElement>
64-
<DynamicElement TagName="button" type="button" class="btn" OnClick="Clear">@ClearText</DynamicElement>
65-
}
66-
@ButtonTemplate
54+
<div class="dropdown-menu-search">
55+
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search" />
56+
<i class="@SearchIconString"></i>
57+
<i class="@SearchLoadingIconString"></i>
6758
</div>
6859
}
69-
@foreach (var itemGroup in Rows.GroupBy(i => i.GroupName))
60+
@if (Rows.Count == 0)
7061
{
71-
if (!string.IsNullOrEmpty(itemGroup.Key))
72-
{
73-
if (GroupItemTemplate != null)
74-
{
75-
@GroupItemTemplate(itemGroup.Key)
76-
}
77-
else
62+
<div class="dropdown-item">@NoSearchDataText</div>
63+
}
64+
else
65+
{
66+
<div class="dropdown-menu-body">
67+
@if (ShowToolbar)
7868
{
79-
<Divider Text="@itemGroup.Key" />
80-
}
81-
}
82-
@foreach (var item in itemGroup)
83-
{
84-
<DynamicElement OnClick="() => ToggleRow(item.Value)" TriggerClick="@CheckCanTrigger(item)" class="@GetItemClassString(item)">
85-
<div class="multi-select-item">
86-
<div class="form-check">
87-
<input class="form-check-input" type="checkbox" disabled="@CheckCanSelect(item)" checked="@GetCheckedString(item)" />
88-
</div>
89-
@if (ItemTemplate != null)
69+
<div class="toolbar">
70+
@if (ShowDefaultButtons)
9071
{
91-
@ItemTemplate(item)
72+
<DynamicElement TagName="button" type="button" class="btn" OnClick="SelectAll">@SelectAllText</DynamicElement>
73+
<DynamicElement TagName="button" type="button" class="btn" OnClick="InvertSelect">@ReverseSelectText</DynamicElement>
74+
<DynamicElement TagName="button" type="button" class="btn" OnClick="Clear">@ClearText</DynamicElement>
9275
}
93-
else if (IsMarkupString)
76+
@ButtonTemplate
77+
</div>
78+
}
79+
@foreach (var itemGroup in Rows.GroupBy(i => i.GroupName))
80+
{
81+
if (!string.IsNullOrEmpty(itemGroup.Key))
82+
{
83+
if (GroupItemTemplate != null)
9484
{
95-
@((MarkupString)item.Text)
85+
@GroupItemTemplate(itemGroup.Key)
9686
}
9787
else
9888
{
99-
<span>@item.Text</span>
89+
<Divider Text="@itemGroup.Key" />
10090
}
101-
</div>
102-
</DynamicElement>
103-
}
104-
}
105-
@if (Rows.Count == 0)
106-
{
107-
<div class="dropdown-item">@NoSearchDataText</div>
91+
}
92+
@foreach (var item in itemGroup)
93+
{
94+
<DynamicElement OnClick="() => ToggleRow(item.Value)" TriggerClick="@CheckCanTrigger(item)" class="@GetItemClassString(item)">
95+
<div class="multi-select-item">
96+
<div class="form-check">
97+
<input class="form-check-input" type="checkbox" disabled="@CheckCanSelect(item)" checked="@GetCheckedString(item)" />
98+
</div>
99+
@if (ItemTemplate != null)
100+
{
101+
@ItemTemplate(item)
102+
}
103+
else if (IsMarkupString)
104+
{
105+
@((MarkupString)item.Text)
106+
}
107+
else
108+
{
109+
<span>@item.Text</span>
110+
}
111+
</div>
112+
</DynamicElement>
113+
}
114+
}
115+
</div>
108116
}
109117
</div>
110118
</div>

src/BootstrapBlazor/Components/Select/MultiSelect.razor.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,6 @@ public partial class MultiSelect<TValue>
4040
.AddClass("d-none", SelectedItems.Count != 0)
4141
.Build();
4242

43-
private string? SearchClassString => CssBuilder.Default("search")
44-
.AddClass("show", ShowSearch)
45-
.Build();
46-
47-
/// <summary>
48-
/// 获得 SearchLoadingIcon 图标字符串
49-
/// </summary>
5043
private string? SearchLoadingIconString => CssBuilder.Default("icon searching-icon")
5144
.AddClass(SearchLoadingIcon)
5245
.Build();

src/BootstrapBlazor/Components/Select/Select.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
@if (ShowSearch)
3535
{
3636
<div class="dropdown-menu-search">
37-
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search">
37+
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search" />
3838
<i class="@SearchIconString"></i>
3939
<i class="@SearchLoadingIconString"></i>
4040
</div>

src/BootstrapBlazor/Components/Select/Select.razor.cs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ public partial class Select<TValue> : ISelect, ILookup
4747
.AddClass(SearchLoadingIcon)
4848
.Build();
4949

50-
private string? DropdownMenuClassString => CssBuilder.Default("dropdown-menu")
51-
.AddClass("is-fixed-search", ShowSearch && IsFixedSearch)
52-
.Build();
53-
5450
private readonly List<SelectedItem> _children = [];
5551

5652
private string? ScrollIntoViewBehaviorString => ScrollIntoViewBehavior == ScrollIntoViewBehavior.Smooth ? null : ScrollIntoViewBehavior.ToDescriptionString();
@@ -68,12 +64,6 @@ public partial class Select<TValue> : ISelect, ILookup
6864
[Parameter]
6965
public Func<string, IEnumerable<SelectedItem>>? OnSearchTextChanged { get; set; }
7066

71-
/// <summary>
72-
/// Gets or sets whether the search bar in the dropdown is fixed. Default is false.
73-
/// </summary>
74-
[Parameter]
75-
public bool IsFixedSearch { get; set; }
76-
7767
/// <summary>
7868
/// Gets or sets whether the select component is editable. Default is false.
7969
/// </summary>
@@ -106,7 +96,7 @@ public partial class Select<TValue> : ISelect, ILookup
10696
public RenderFragment<SelectedItem?>? DisplayTemplate { get; set; }
10797

10898
/// <summary>
109-
/// Gets or sets whether virtual scrolling is enabled. Default is false. Note: When virtual scrolling is enabled, <see cref="SelectBase{TValue}.ShowSearch"/>, <see cref="PopoverSelectBase{TValue}.IsPopover"/>, and <seealso cref="IsFixedSearch"/> are not supported. Set <see cref="DefaultVirtualizeItemText"/> when setting initial values.
99+
/// Gets or sets whether virtual scrolling is enabled. Default is false.
110100
/// </summary>
111101
[Parameter]
112102
public bool IsVirtualize { get; set; }
@@ -397,13 +387,6 @@ private async ValueTask<ItemsProviderResult<SelectedItem>> LoadItems(ItemsProvid
397387
int GetCountByTotal() => TotalCount == 0 ? request.Count : Math.Min(request.Count, TotalCount - request.StartIndex);
398388
}
399389

400-
private async Task SearchTextChanged(string val)
401-
{
402-
_itemsCache = null;
403-
SearchText = val;
404-
await RefreshVirtualizeElement();
405-
}
406-
407390
private async Task RefreshVirtualizeElement()
408391
{
409392
if (IsVirtualize && OnQueryAsync != null)
@@ -473,7 +456,9 @@ public async Task ConfirmSelectedItem(int index)
473456
[JSInvokable]
474457
public async Task TriggerOnSearch(string searchText)
475458
{
476-
await SearchTextChanged(searchText);
459+
_itemsCache = null;
460+
SearchText = searchText;
461+
await RefreshVirtualizeElement();
477462
StateHasChanged();
478463
}
479464

src/BootstrapBlazor/Components/Select/SelectBase.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ public abstract class SelectBase<TValue> : PopoverSelectBase<TValue>
2323
[Parameter]
2424
public bool ShowSearch { get; set; }
2525

26+
/// <summary>
27+
/// Gets or sets whether the search bar in the dropdown is fixed. Default is false.
28+
/// </summary>
29+
[Parameter]
30+
public bool IsFixedSearch { get; set; }
31+
2632
/// <summary>
2733
/// Gets or sets the search icon.
2834
/// </summary>
@@ -115,6 +121,13 @@ public abstract class SelectBase<TValue> : PopoverSelectBase<TValue>
115121
.AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
116122
.Build();
117123

124+
/// <summary>
125+
/// Gets the dropdown menu class string.
126+
/// </summary>
127+
protected string? DropdownMenuClassString => CssBuilder.Default("dropdown-menu")
128+
.AddClass("is-fixed-search", ShowSearch && IsFixedSearch)
129+
.Build();
130+
118131
/// <summary>
119132
/// <inheritdoc/>
120133
/// </summary>

src/BootstrapBlazor/Components/SelectGeneric/SelectGeneric.razor

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@
3030
{
3131
<span class="@ClearClassString" @onclick="OnClearValue"><i class="@ClearIcon"></i></span>
3232
}
33-
<div class="dropdown-menu">
34-
<div class="@SearchClassString">
35-
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search">
36-
<i class="@SearchIconString"></i>
37-
<i class="@SearchLoadingIconString"></i>
38-
</div>
33+
<div class="@DropdownMenuClassString">
34+
@if (ShowSearch)
35+
{
36+
<div class="dropdown-menu-search">
37+
<input type="text" class="search-text form-control" autocomplete="off" value="@SearchText" aria-label="search" />
38+
<i class="@SearchIconString"></i>
39+
<i class="@SearchLoadingIconString"></i>
40+
</div>
41+
}
3942
@if (IsVirtualize)
4043
{
4144
<div class="dropdown-virtual">
@@ -49,6 +52,10 @@
4952
}
5053
</div>
5154
}
55+
else if (Rows.Count == 0)
56+
{
57+
<div class="dropdown-item">@NoSearchDataText</div>
58+
}
5259
else
5360
{
5461
@foreach (var itemGroup in Rows.GroupBy(i => i.GroupName))
@@ -69,10 +76,6 @@
6976
@RenderRow(item)
7077
}
7178
}
72-
@if (Rows.Count == 0)
73-
{
74-
<div class="dropdown-item">@NoSearchDataText</div>
75-
}
7679
}
7780
</div>
7881
@if (!IsPopover)

0 commit comments

Comments
 (0)