Skip to content

Commit 22fbbc9

Browse files
committed
feat: 增加虚拟化功能
1 parent 6569ed7 commit 22fbbc9

File tree

3 files changed

+99
-12
lines changed

3 files changed

+99
-12
lines changed

src/BootstrapBlazor/Components/AutoFill/AutoFill.razor

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@namespace BootstrapBlazor.Components
2+
@using Microsoft.AspNetCore.Components.Web.Virtualization
23
@typeparam TValue
34
@inherits PopoverCompleteBase<TValue>
45

@@ -18,22 +19,53 @@
1819
<span class="form-select-append"><i class="@Icon"></i></span>
1920
<span class="form-select-append ac-loading"><i class="@LoadingIcon"></i></span>
2021
<ul class="dropdown-menu">
21-
@foreach (var item in Rows)
22+
@if (IsVirtualize)
2223
{
23-
<li @key="@item" class="dropdown-item" @onclick="() => OnClickItem(item)">
24-
@if (ItemTemplate != null)
24+
<div class="dropdown-menu-body dropdown-virtual">
25+
@if (OnQueryAsync == null)
2526
{
26-
@ItemTemplate(item)
27+
<Virtualize ItemSize="RowHeight" OverscanCount="OverscanCount" Items="@GetVirtualItems()" ChildContent="RenderRow">
28+
</Virtualize>
2729
}
2830
else
2931
{
30-
<div>@GetDisplayText(item)</div>
32+
<Virtualize ItemSize="RowHeight" OverscanCount="OverscanCount" ItemsProvider="LoadItems"
33+
Placeholder="RenderPlaceHolderRow" ItemContent="RenderRow" @ref="_virtualizeElement">
34+
</Virtualize>
3135
}
32-
</li>
36+
</div>
3337
}
34-
@if (ShowNoDataTip && Rows.Count == 0)
38+
else if (ShowNoDataTip && Rows.Count == 0)
3539
{
3640
<li class="dropdown-item">@NoDataTip</li>
3741
}
42+
else
43+
{
44+
<div class="dropdown-menu-body">
45+
@foreach (var item in Rows)
46+
{
47+
@RenderRow(item)
48+
}
49+
</div>
50+
}
3851
</ul>
3952
</div>
53+
54+
@code {
55+
RenderFragment<TValue> RenderRow => item =>
56+
@<li @key="@item" class="dropdown-item" @onclick="() => OnClickItem(item)">
57+
@if (ItemTemplate != null)
58+
{
59+
@ItemTemplate(item)
60+
}
61+
else
62+
{
63+
<div>@GetDisplayText(item)</div>
64+
}
65+
</li>;
66+
67+
RenderFragment<PlaceholderContext> RenderPlaceHolderRow => context =>
68+
@<div class="dropdown-item">
69+
<div class="is-ph"></div>
70+
</div>;
71+
}

src/BootstrapBlazor/Components/AutoFill/AutoFill.razor.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
55

6+
using Microsoft.AspNetCore.Components.Web.Virtualization;
67
using Microsoft.Extensions.Localization;
78

89
namespace BootstrapBlazor.Components;
@@ -97,6 +98,33 @@ public partial class AutoFill<TValue>
9798
[Parameter]
9899
public bool IsVirtualize { get; set; }
99100

101+
/// <summary>
102+
/// Gets or sets the row height for virtual scrolling. Default is 33.
103+
/// </summary>
104+
/// <remarks>Effective when <see cref="IsVirtualize"/> is set to true.</remarks>
105+
[Parameter]
106+
public float RowHeight { get; set; } = 33f;
107+
108+
/// <summary>
109+
/// Gets or sets the overscan count for virtual scrolling. Default is 4.
110+
/// </summary>
111+
/// <remarks>Effective when <see cref="IsVirtualize"/> is set to true.</remarks>
112+
[Parameter]
113+
public int OverscanCount { get; set; } = 4;
114+
115+
/// <summary>
116+
/// Gets or sets the callback method for loading virtualized items.
117+
/// </summary>
118+
[Parameter]
119+
[NotNull]
120+
public Func<VirtualizeQueryOption, Task<QueryData<TValue>>>? OnQueryAsync { get; set; }
121+
122+
/// <summary>
123+
/// Gets or sets whether the select component is clearable. Default is false.
124+
/// </summary>
125+
[Parameter]
126+
public bool IsClearable { get; set; }
127+
100128
[Inject]
101129
[NotNull]
102130
private IStringLocalizer<AutoComplete>? Localizer { get; set; }
@@ -107,6 +135,9 @@ public partial class AutoFill<TValue>
107135

108136
private List<TValue>? _filterItems;
109137

138+
[NotNull]
139+
private Virtualize<TValue>? _virtualizeElement = default;
140+
110141
/// <summary>
111142
/// <inheritdoc/>
112143
/// </summary>
@@ -142,6 +173,34 @@ private async Task OnClickItem(TValue val)
142173

143174
private List<TValue> Rows => _filterItems ?? [.. Items];
144175

176+
private int _totalCount;
177+
private TValue? _itemsCache;
178+
private ItemsProviderResult<TValue> _result;
179+
180+
private async ValueTask<ItemsProviderResult<TValue>> LoadItems(ItemsProviderRequest request)
181+
{
182+
// 有搜索条件时使用原生请求数量
183+
// 有总数时请求剩余数量
184+
var count = _totalCount == 0 ? request.Count : Math.Min(request.Count, _totalCount - request.StartIndex);
185+
var data = await OnQueryAsync(new() { StartIndex = request.StartIndex, Count = count });
186+
187+
_itemsCache = default;
188+
_totalCount = data.TotalCount;
189+
var items = data.Items ?? [];
190+
_result = new ItemsProviderResult<TValue>(items, _totalCount);
191+
return _result;
192+
}
193+
194+
private List<TValue> GetVirtualItems()
195+
{
196+
var items = new List<TValue>();
197+
if (Items != null)
198+
{
199+
items.AddRange(Items);
200+
}
201+
return items;
202+
}
203+
145204
/// <summary>
146205
/// Triggers the filter method.
147206
/// </summary>
Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
11
.auto-fill {
2-
--bb-af-dropdown-max-height: var(--bb-dropdown-max-height);
3-
4-
.dropdown-menu {
5-
max-height: var(--bb-af-dropdown-max-height);
6-
}
2+
--bb-dropdown-max-height: 330px;
73
}

0 commit comments

Comments
 (0)