Skip to content

Commit ac1453f

Browse files
authored
fix(Table): add filter table column state logic (#8036)
* doc: 代码格式化 * refactor: 增加显示名称赋值逻辑 * refactor: 移除逻辑使用内联实现 * refactor: 重构获得可见列逻辑 * chore: bump version 10.6.2 * test: 增加单元测试 * test: 更改单元测试 * refactor: 重构代码逻辑提高可读性 * test: 增加宽度设置单元测试 * refactor: 增加保护逻辑 * refactor: 精简逻辑 * test: 更新单元测试
1 parent b46fc7f commit ac1453f

5 files changed

Lines changed: 101 additions & 45 deletions

File tree

‎src/BootstrapBlazor/BootstrapBlazor.csproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>10.6.2-beta02</Version>
4+
<Version>10.6.2</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

‎src/BootstrapBlazor/Components/Table/Table.razor‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -842,17 +842,17 @@
842842

843843
RenderFragment RenderPagination =>
844844
@<Pagination PageCount="@PageCount" PageIndex="@PageIndex" MaxPageLinkCount="MaxPageLinkCount"
845-
OnPageLinkClick="@OnPageLinkClick"
846-
ShowGotoNavigator="ShowGotoNavigator" GotoTemplate="GotoTemplate!"
847-
GotoNavigatorLabelText="@GotoNavigatorLabelText"
848-
ShowPageInfo="ShowPageInfo" PageInfoTemplate="InternalPageInfoTemplate"></Pagination>;
845+
OnPageLinkClick="@OnPageLinkClick"
846+
ShowGotoNavigator="ShowGotoNavigator" GotoTemplate="GotoTemplate!"
847+
GotoNavigatorLabelText="@GotoNavigatorLabelText"
848+
ShowPageInfo="ShowPageInfo" PageInfoTemplate="InternalPageInfoTemplate"></Pagination>;
849849

850850
RenderFragment<TableColumnState> RenderColumnListItem => item =>
851851
@<div class="dropdown-item">
852852
<Checkbox ShowAfterLabel="true" DisplayText="@item.DisplayName"
853-
IsDisabled="@GetColumnsListState(item)"
854-
Value="@item.Visible"
855-
OnValueChanged="visible => OnToggleColumnVisible(item, visible)">
853+
IsDisabled="@GetColumnsListState(item)"
854+
Value="@item.Visible"
855+
OnValueChanged="visible => OnToggleColumnVisible(item, visible)">
856856
</Checkbox>
857857
</div>;
858858

@@ -1080,7 +1080,7 @@
10801080
@if (GetShowRowCheckbox(item))
10811081
{
10821082
<Checkbox TValue="TItem" Value="@item" State="@RowCheckState(item)"
1083-
OnStateChanged="OnCheck" StopPropagation="true">
1083+
OnStateChanged="OnCheck" StopPropagation="true">
10841084
</Checkbox>
10851085
}
10861086
</div>

‎src/BootstrapBlazor/Components/Table/Table.razor.Toolbar.cs‎

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -554,27 +554,6 @@ public Func<TItem, bool>? ShowDeleteButtonCallback
554554
/// </summary>
555555
public List<ITableColumn> GetVisibleColumns() => _visibleColumnsCache;
556556

557-
private void ResetVisibleColumnsCache()
558-
{
559-
_visibleColumnsCache.Clear();
560-
561-
for (var index = 0; index < _tableColumnStates.Count; index++)
562-
{
563-
var item = _tableColumnStates[index];
564-
var col = Columns.Find(c => c.GetFieldName() == item.Name);
565-
if (col != null)
566-
{
567-
item.DisplayName = col.GetDisplayName();
568-
569-
if (item.Visible)
570-
{
571-
// 增加到可见列缓存集合
572-
_visibleColumnsCache.Add(col);
573-
}
574-
}
575-
}
576-
}
577-
578557
private bool GetColumnsListState(TableColumnState item)
579558
{
580559
var items = _tableColumnStates.Where(i => i.Visible).Select(a => a.Name).ToHashSet();

‎src/BootstrapBlazor/Components/Table/Table.razor.cs‎

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,38 +1346,100 @@ private async Task LoadTableColumnStates()
13461346

13471347
private void ResetTableColumns()
13481348
{
1349+
_visibleColumnsCache.Clear();
1350+
13491351
if (_tableColumnStates.Count == 0)
13501352
{
13511353
// 重建缓存
1352-
_tableColumnStates.AddRange(Columns.Where(i => !i.GetIgnore()).Select(CreateTableColumnState));
1354+
for (var index = 0; index < Columns.Count; index++)
1355+
{
1356+
var col = Columns[index];
1357+
if (col.GetIgnore())
1358+
{
1359+
continue;
1360+
}
1361+
1362+
var state = CreateTableColumnState(col);
1363+
_tableColumnStates.Add(state);
1364+
1365+
if (col.GetVisible(_screenSize))
1366+
{
1367+
_visibleColumnsCache.Add(col);
1368+
}
1369+
}
13531370
}
13541371
else
13551372
{
1373+
// 过滤掉 Columns 中不存在或被忽略的列
1374+
// 注意由于多语言导致的相同列显示名称不同的情况
1375+
// 通过字典缓存避免 Columns.Exists / _tableColumnStates.Find 的二次嵌套循环 O(N*M)
1376+
var columnMap = new Dictionary<string, ITableColumn>(Columns.Count, StringComparer.Ordinal);
13561377
foreach (var col in Columns)
13571378
{
1358-
var item = _tableColumnStates.Find(i => i.Name == col.GetFieldName());
1379+
if (!col.GetIgnore())
1380+
{
1381+
columnMap[col.GetFieldName()] = col;
1382+
}
1383+
}
1384+
1385+
var stateMap = new Dictionary<string, TableColumnState>(_tableColumnStates.Count, StringComparer.Ordinal);
1386+
for (var i = _tableColumnStates.Count - 1; i >= 0; i--)
1387+
{
1388+
var item = _tableColumnStates[i];
1389+
1390+
// 移除不合格的列状态项
1391+
if (string.IsNullOrEmpty(item.Name))
1392+
{
1393+
_tableColumnStates.RemoveAt(i);
1394+
continue;
1395+
}
1396+
1397+
if (columnMap.ContainsKey(item.Name))
1398+
{
1399+
stateMap[item.Name] = item;
1400+
}
1401+
else
1402+
{
1403+
_tableColumnStates.RemoveAt(i);
1404+
}
1405+
}
13591406

1407+
foreach (var col in Columns)
1408+
{
13601409
if (col.GetIgnore())
13611410
{
1362-
if (item != null)
1363-
{
1364-
_tableColumnStates.Remove(item);
1365-
}
13661411
continue;
13671412
}
13681413

1369-
if (item == null)
1414+
var name = col.GetFieldName();
1415+
if (stateMap.TryGetValue(name, out var item))
1416+
{
1417+
item.DisplayName = col.GetDisplayName();
1418+
}
1419+
else
13701420
{
1371-
_tableColumnStates.Add(CreateTableColumnState(col));
1421+
item = CreateTableColumnState(col);
1422+
_tableColumnStates.Add(item);
13721423
}
13731424
}
1374-
}
13751425

1376-
ResetVisibleColumnsCache();
1426+
// 根据 _tableColumnStates 顺序重建可见列顺序
1427+
for (var index = 0; index < _tableColumnStates.Count; index++)
1428+
{
1429+
var item = _tableColumnStates[index];
1430+
var col = columnMap[item.Name];
1431+
if (item.Visible)
1432+
{
1433+
// 增加到可见列缓存集合
1434+
_visibleColumnsCache.Add(col);
1435+
}
1436+
}
1437+
}
13771438
}
13781439

13791440
private TableColumnState CreateTableColumnState(ITableColumn col) => new TableColumnState()
13801441
{
1442+
DisplayName = col.GetDisplayName(),
13811443
Name = col.GetFieldName(),
13821444
Width = col.Width,
13831445
Visible = col.GetVisible(_screenSize)

‎test/UnitTest/Components/TableTest.cs‎

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -273,8 +273,8 @@ public async Task ResetVisibleColumns_Ok()
273273
var table = cut.FindComponent<Table<Foo>>();
274274
await cut.InvokeAsync(() => table.Instance.ResetVisibleColumns(
275275
[
276-
new TableColumnState() { Name = nameof(Foo.Name), Visible = true, DisplayName = "Name-Display" },
277-
new TableColumnState() { Name = nameof(Foo.Address), Visible = false }
276+
new TableColumnState() { Name = nameof(Foo.Name), Visible = true, Width = 120 },
277+
new TableColumnState() { Name = nameof(Foo.Address), Visible = false, Width = 100 }
278278
]));
279279

280280
Assert.Single(table.Instance.GetVisibleColumns());
@@ -284,6 +284,9 @@ await cut.InvokeAsync(() => table.Instance.ResetVisibleColumns(
284284
Assert.Equal(2, labels.Count);
285285
Assert.Equal("姓名", labels[0].TextContent);
286286
Assert.Equal("地址", labels[1].TextContent);
287+
288+
// 检查宽度设置
289+
Assert.Contains("<col style=\"width: 120px;\" />", table.Markup);
287290
}
288291

289292
[Fact]
@@ -902,7 +905,9 @@ public async Task ShowColumnList_Ok()
902905
state.Columns = new List<TableColumnState>()
903906
{
904907
new TableColumnState() { Name = nameof(Foo.Name), Visible = false },
905-
new TableColumnState() { Name = nameof(Foo.Address), Visible = true, Width = 120 }
908+
new TableColumnState() { Name = nameof(Foo.Address), Visible = true, Width = 120 },
909+
// 增加一列 Columns 中不存在的列
910+
new TableColumnState() { Name = nameof(Foo.Count), Visible = true, Width = 120 }
906911
};
907912

908913
Context.JSInterop.Setup<TableColumnClientStatus>("getColumnStates", "test").SetResult(state);
@@ -945,6 +950,12 @@ public async Task ShowColumnList_Ok()
945950
cut.Contains("Test_Column_List");
946951
cut.DoesNotContain("dropdown-menu-popover");
947952

953+
// 过滤掉 Count 列只显示 Name 和 Address 列
954+
var labels = cut.FindAll(".form-check-label");
955+
Assert.Equal(2, labels.Count);
956+
Assert.Equal("姓名", labels[0].TextContent);
957+
Assert.Equal("地址", labels[1].TextContent);
958+
948959
var item = cut.FindComponents<Checkbox<bool>>()[0];
949960
await cut.InvokeAsync(item.Instance.OnToggleClick);
950961
Assert.True(show);
@@ -981,7 +992,7 @@ public async Task ShowColumnList_Ok()
981992
cut.Contains("style=\"width: 340px;\"");
982993

983994
// 检查 ShowColumnList 中的 DisplayName 是否正确
984-
var labels = table.FindAll(".form-check-label");
995+
labels = table.FindAll(".form-check-label");
985996
Assert.Equal(2, labels.Count);
986997
Assert.Equal("姓名", labels[0].TextContent);
987998
Assert.Equal("地址", labels[1].TextContent);
@@ -7978,6 +7989,7 @@ await cut.WaitForAssertionAsync(() =>
79787989
});
79797990

79807991
// 二次渲染触发 OnColumnCreating
7992+
// 虽然更改了 Visible 但是以持久化的为准,更改 visible 变量不影响渲染结果
79817993
visible = true;
79827994
creating = false;
79837995
cut.Render();
@@ -7986,7 +7998,7 @@ await cut.WaitForAssertionAsync(() =>
79867998
{
79877999
Assert.True(creating);
79888000
var table = cut.FindComponent<Table<Foo>>();
7989-
Assert.Equal(2, table.Instance.GetVisibleColumns().Count);
8001+
Assert.Single(table.Instance.GetVisibleColumns());
79908002
});
79918003
}
79928004

@@ -8961,6 +8973,9 @@ public async Task OnLoadTableColumnClientStatus_Ok()
89618973
state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Name), Visible = true, Width = 100, DisplayName = "Name-Display" });
89628974
state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Address), Visible = false, Width = 120, DisplayName = "Address-Display" });
89638975

8976+
// 增加干扰列
8977+
state.Columns.Add(new TableColumnState() { Name = "", Visible = true });
8978+
89648979
var loaded = false;
89658980
var localizer = Context.Services.GetRequiredService<IStringLocalizer<Foo>>();
89668981
var items = Foo.GenerateFoo(localizer, 2);

0 commit comments

Comments
 (0)