From 72ffffabc2cd18f87264e3aec1fd45ec1b66b752 Mon Sep 17 00:00:00 2001
From: Tony996 <6914529@qq.com>
Date: Fri, 12 Jun 2026 16:19:40 +0800
Subject: [PATCH 1/5] =?UTF-8?q?Table=E7=BB=84=E4=BB=B6=E8=83=BD=E5=90=A6?=
=?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8A=A8=E6=80=81=E8=AE=BE=E7=BD=AE=E5=9B=BA?=
=?UTF-8?q?=E5=AE=9A=E5=88=97=E7=9A=84=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
refactor: 可以动态设置固定列,同时固定列支持表格持久化
---
.../Components/Table/Table.razor.cs | 26 +++++++++-
.../Components/Table/Table.razor.js | 20 ++++++--
.../Components/Table/TableColumnState.cs | 6 +++
test/UnitTest/Components/TableTest.cs | 49 +++++++++++++++++++
4 files changed, 97 insertions(+), 4 deletions(-)
diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.cs b/src/BootstrapBlazor/Components/Table/Table.razor.cs
index 8b71d314d81..328f6ee3b35 100644
--- a/src/BootstrapBlazor/Components/Table/Table.razor.cs
+++ b/src/BootstrapBlazor/Components/Table/Table.razor.cs
@@ -1435,6 +1435,7 @@ private void ResetTableColumns()
{
var item = _tableColumnStates[index];
var col = columnMap[item.Name];
+ col.Fixed = !string.IsNullOrEmpty(item.Name) && stateMap.TryGetValue(item.Name, out var state) ? stateMap[item.Name].Fixed : false;
if (item.Visible)
{
// 增加到可见列缓存集合
@@ -1449,7 +1450,8 @@ private void ResetTableColumns()
DisplayName = col.GetDisplayName(),
Name = col.GetFieldName(),
Width = col.Fixed && !col.Width.HasValue ? DefaultFixedColumnWidth : col.Width,
- Visible = col.GetVisible(_screenSize)
+ Visible = col.GetVisible(_screenSize),
+ Fixed = col.Fixed
};
private async Task OnTableRenderAsync(bool firstRender)
@@ -1940,6 +1942,28 @@ public async Task FitAllColumnWidth()
await InvokeVoidAsync("fitAllColumnWidth", Id);
}
+ ///
+ /// 更新表格列客户端状态方法
+ /// Update Table Column Client Status Method
+ ///
+ ///
+ public async Task UpdateTableColumnClientStatus()
+ {
+ if (Columns.Count != 0)
+ {
+ // 用户在外面变更了列状态后,为避免用户变更状态丢失,须将变更后的状态同步到缓存中
+ foreach (var item in Columns)
+ {
+ _tableColumnStates.Find(x => x.Name == item.GetFieldName())!.Fixed = item.Fixed;
+ }
+ StateHasChanged();
+ }
+ // 如果启用了 ClientTableName 则更新浏览器持久化列状态
+ await InvokeVoidAsync("updateColumnStates", Id);
+
+ return _tableColumnStateCache;
+ }
+
///
/// 清除表格列客户端状态实例方法
/// clear table column client status instance method
diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.js b/src/BootstrapBlazor/Components/Table/Table.razor.js
index 94804c8322e..48f02cfef78 100644
--- a/src/BootstrapBlazor/Components/Table/Table.razor.js
+++ b/src/BootstrapBlazor/Components/Table/Table.razor.js
@@ -586,7 +586,7 @@ const autoFitColumnWidth = async (table, col) => {
const index = indexOfCol(col);
let rows = null;
let maxWidth = getColumnMaxCellWidth(table, index);
-
+
if (table.options.fitColumnWidthIncludeHeader) {
const th = getColumnHeader(col);
maxWidth = Math.max(maxWidth, getCellWidth(th));
@@ -936,6 +936,18 @@ const removeColumnWidthState = tableName => {
localStorage.removeItem(columnWidthKey);
}
+export function updateColumnStates(id) {
+ const el = document.getElementById(id)
+ if (el === null) {
+ return
+ }
+ let table = Data.get(id)
+ table.el = el;
+ Data.set(id, table)
+ const state = getColumnStateObject(table);
+ saveColumnStateToLocalstorage(table, state);
+
+}
export function clearColumnStates(tableName) {
const columnStateKey = `bb-table-${tableName}`;
localStorage.removeItem(columnStateKey);
@@ -976,7 +988,8 @@ const getColumnStateObject = table => {
return {
name: col.name,
width: getColumnWidth(col, table.columns),
- visible: col.visible
+ visible: col.visible,
+ fixed: col.fixed
}
}),
table: getTableWidth(table.tables[0])
@@ -988,7 +1001,8 @@ const getColumnStateObject = table => {
return {
name: getColumnName(col),
width: getResizableColumnWidth(col),
- visible: true
+ visible: true,
+ fixed: getColumnHeader(col).classList.contains('fixed')
}
}),
table: getTableWidth(table.tables[0])
diff --git a/src/BootstrapBlazor/Components/Table/TableColumnState.cs b/src/BootstrapBlazor/Components/Table/TableColumnState.cs
index 1aad8e442d8..3a2e181395a 100644
--- a/src/BootstrapBlazor/Components/Table/TableColumnState.cs
+++ b/src/BootstrapBlazor/Components/Table/TableColumnState.cs
@@ -38,4 +38,10 @@ public class TableColumnState
/// Gets or sets column width
///
public int? Width { get; set; }
+
+ ///
+ /// 获得/设置 列固定
+ /// Gets or sets column fixed
+ ///
+ public bool Fixed { get; set; }
}
diff --git a/test/UnitTest/Components/TableTest.cs b/test/UnitTest/Components/TableTest.cs
index 3f48b29f279..41329364b4e 100644
--- a/test/UnitTest/Components/TableTest.cs
+++ b/test/UnitTest/Components/TableTest.cs
@@ -9018,6 +9018,55 @@ public async Task OnTableColumnClientStatusChanged_ResizeColumn_Ok()
Assert.NotNull(clientState);
}
+ [Fact]
+ public async Task UpdateTableColumnClientStatus_Ok()
+ {
+ var state = new TableColumnClientStatus();
+ state.TableWidth = 220;
+ state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Name), Visible = true, Width = 100, Fixed = true });
+ state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Address), Visible = true, Width = 120, Fixed = false });
+
+ Context.JSInterop.Setup("getColumnStates", "test_update").SetResult(state);
+ var invoker = Context.JSInterop.SetupVoid("clearColumnStates", "test_update");
+ invoker.SetVoidResult();
+
+ var localizer = Context.Services.GetRequiredService>();
+ var cut = Context.Render(pb =>
+ {
+ pb.AddChildContent>(pb =>
+ {
+ pb.Add(a => a.ClientTableName, "test_update");
+ pb.Add(a => a.RenderMode, TableRenderMode.Table);
+ pb.Add(a => a.AllowResizing, true);
+ pb.Add(a => a.OnQueryAsync, OnQueryAsync(localizer));
+ pb.Add(a => a.TableColumns, foo => builder =>
+ {
+ builder.OpenComponent>(0);
+ builder.AddAttribute(1, "Field", "Name");
+ builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string)));
+ builder.AddAttribute(3, "Width", 80);
+ builder.CloseComponent();
+
+ builder.OpenComponent>(0);
+ builder.AddAttribute(3, "Field", "Address");
+ builder.AddAttribute(4, "FieldExpression", Utility.GenerateValueExpression(foo, "Address", typeof(string)));
+ builder.CloseComponent();
+ });
+ });
+ });
+
+ // 由于启用了客户端持久化 Name 列宽使用 100 而非 80
+ var table = cut.FindComponent>();
+ var colGroup = table.Find("colgroup");
+ Assert.Contains("style=\"width: 100px;\"", colGroup.ToMarkup());
+ Assert.Contains("style=\"width: 120px;\"", colGroup.ToMarkup());
+
+
+ var status = await cut.InvokeAsync(() => table.Instance.UpdateTableColumnClientStatus());
+ Assert.Equal(true, status.Columns[0].Fixed);
+ Assert.Equal(state.Columns.Count, status.Columns.Count);
+ }
+
[Fact]
public async Task ClearTableColumnClientStatus_Ok()
{
From 74435e64a1451bd800b3a94dc9e47d15d209a49a Mon Sep 17 00:00:00 2001
From: Tony996 <6914529@qq.com>
Date: Fri, 12 Jun 2026 16:50:03 +0800
Subject: [PATCH 2/5] =?UTF-8?q?=E6=B8=85=E9=99=A4=E7=A9=BA=E8=A1=8C?=
=?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E7=BC=93=E5=AD=98=E5=88=97=E5=8F=AF?=
=?UTF-8?q?=E8=83=BD=E4=B8=BA=E5=88=A4=E6=96=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
refactor:清除空行,增加缓存列可能为判断
---
src/BootstrapBlazor/Components/Table/Table.razor.cs | 6 +++++-
src/BootstrapBlazor/Components/Table/Table.razor.js | 1 -
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.cs b/src/BootstrapBlazor/Components/Table/Table.razor.cs
index 328f6ee3b35..4f7045596f3 100644
--- a/src/BootstrapBlazor/Components/Table/Table.razor.cs
+++ b/src/BootstrapBlazor/Components/Table/Table.razor.cs
@@ -1954,7 +1954,11 @@ public async Task UpdateTableColumnClientStatus()
// 用户在外面变更了列状态后,为避免用户变更状态丢失,须将变更后的状态同步到缓存中
foreach (var item in Columns)
{
- _tableColumnStates.Find(x => x.Name == item.GetFieldName())!.Fixed = item.Fixed;
+ var columnState = _tableColumnStates.Find(x => x.Name == item.GetFieldName());
+ if (columnState != null)
+ {
+ columnState.Fixed = item.Fixed;
+ }
}
StateHasChanged();
}
diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.js b/src/BootstrapBlazor/Components/Table/Table.razor.js
index 48f02cfef78..0de8d1c639b 100644
--- a/src/BootstrapBlazor/Components/Table/Table.razor.js
+++ b/src/BootstrapBlazor/Components/Table/Table.razor.js
@@ -946,7 +946,6 @@ export function updateColumnStates(id) {
Data.set(id, table)
const state = getColumnStateObject(table);
saveColumnStateToLocalstorage(table, state);
-
}
export function clearColumnStates(tableName) {
const columnStateKey = `bb-table-${tableName}`;
From d2b777569f73370f2b43489ee1ea52cca450b05a Mon Sep 17 00:00:00 2001
From: Tony996 <6914529@qq.com>
Date: Fri, 12 Jun 2026 20:41:34 +0800
Subject: [PATCH 3/5] =?UTF-8?q?refactor:=20=E8=A1=A5=E5=85=85=E5=8A=A8?=
=?UTF-8?q?=E6=80=81=E5=9B=BA=E5=AE=9A=E5=88=97=E6=97=B6=EF=BC=8C=E6=B2=A1?=
=?UTF-8?q?=E6=9C=89=E5=88=97=E5=AE=BD=E7=BB=99=E9=BB=98=E8=AE=A4=E5=88=97?=
=?UTF-8?q?=E5=AE=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
refactor: 补充动态固定列时,没有列宽给默认列宽,以防止无列宽时固定后,横向滑动出现错位
---
src/BootstrapBlazor/Components/Table/Table.razor.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.cs b/src/BootstrapBlazor/Components/Table/Table.razor.cs
index 4f7045596f3..95695da3ec0 100644
--- a/src/BootstrapBlazor/Components/Table/Table.razor.cs
+++ b/src/BootstrapBlazor/Components/Table/Table.razor.cs
@@ -1958,6 +1958,7 @@ public async Task UpdateTableColumnClientStatus()
if (columnState != null)
{
columnState.Fixed = item.Fixed;
+ columnState.Width = item.Width.HasValue ? item.Width : (item.Fixed ? DefaultFixedColumnWidth : null);
}
}
StateHasChanged();
From 02a3face8abcb188b16342b0f57cd35a2938941b Mon Sep 17 00:00:00 2001
From: Tony996 <6914529@qq.com>
Date: Fri, 12 Jun 2026 23:16:50 +0800
Subject: [PATCH 4/5] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=8D=95=E5=85=83?=
=?UTF-8?q?=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
refactor: 调整指定固定列时,列宽必须有值
test:补充单元测试
---
.../Components/Table/Table.razor.cs | 2 +-
test/UnitTest/Components/TableTest.cs | 20 ++++++++++++++-----
2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/BootstrapBlazor/Components/Table/Table.razor.cs b/src/BootstrapBlazor/Components/Table/Table.razor.cs
index 95695da3ec0..65cce099d97 100644
--- a/src/BootstrapBlazor/Components/Table/Table.razor.cs
+++ b/src/BootstrapBlazor/Components/Table/Table.razor.cs
@@ -1958,7 +1958,7 @@ public async Task UpdateTableColumnClientStatus()
if (columnState != null)
{
columnState.Fixed = item.Fixed;
- columnState.Width = item.Width.HasValue ? item.Width : (item.Fixed ? DefaultFixedColumnWidth : null);
+ columnState.Width = item.Fixed && !item.Width.HasValue ? DefaultFixedColumnWidth : item.Width;
}
}
StateHasChanged();
diff --git a/test/UnitTest/Components/TableTest.cs b/test/UnitTest/Components/TableTest.cs
index 41329364b4e..e610b54aae2 100644
--- a/test/UnitTest/Components/TableTest.cs
+++ b/test/UnitTest/Components/TableTest.cs
@@ -9023,11 +9023,11 @@ public async Task UpdateTableColumnClientStatus_Ok()
{
var state = new TableColumnClientStatus();
state.TableWidth = 220;
- state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Name), Visible = true, Width = 100, Fixed = true });
+ state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Name), Visible = true, Fixed = true });
state.Columns.Add(new TableColumnState() { Name = nameof(Foo.Address), Visible = true, Width = 120, Fixed = false });
Context.JSInterop.Setup("getColumnStates", "test_update").SetResult(state);
- var invoker = Context.JSInterop.SetupVoid("clearColumnStates", "test_update");
+ var invoker = Context.JSInterop.SetupVoid("updateColumnStates", "test_update");
invoker.SetVoidResult();
var localizer = Context.Services.GetRequiredService>();
@@ -9044,7 +9044,7 @@ public async Task UpdateTableColumnClientStatus_Ok()
builder.OpenComponent>(0);
builder.AddAttribute(1, "Field", "Name");
builder.AddAttribute(2, "FieldExpression", Utility.GenerateValueExpression(foo, "Name", typeof(string)));
- builder.AddAttribute(3, "Width", 80);
+ builder.AddAttribute(3, "Fixed", true);
builder.CloseComponent();
builder.OpenComponent>(0);
@@ -9058,13 +9058,23 @@ public async Task UpdateTableColumnClientStatus_Ok()
// 由于启用了客户端持久化 Name 列宽使用 100 而非 80
var table = cut.FindComponent>();
var colGroup = table.Find("colgroup");
- Assert.Contains("style=\"width: 100px;\"", colGroup.ToMarkup());
Assert.Contains("style=\"width: 120px;\"", colGroup.ToMarkup());
-
var status = await cut.InvokeAsync(() => table.Instance.UpdateTableColumnClientStatus());
Assert.Equal(true, status.Columns[0].Fixed);
Assert.Equal(state.Columns.Count, status.Columns.Count);
+
+ table = cut.FindComponent>();
+ var columns = cut.FindAll("th");
+ colGroup = table.Find("colgroup");
+ Assert.Contains("style=\"width: 200px;\"", colGroup.ToMarkup());
+ if (columns[0].ClassName.Contains("fixed"))
+ {
+ var fixedWidth = cut.FindAll("col")[0].OuterHtml.Contains("width: 200px");
+ Assert.Equal("fixedWidth:True", $"fixedWidth:{fixedWidth}");
+ }
+
+
}
[Fact]
From 33988986414bc92fba998f00fd5e4ee679427e6b Mon Sep 17 00:00:00 2001
From: Tony996 <6914529@qq.com>
Date: Fri, 12 Jun 2026 23:20:20 +0800
Subject: [PATCH 5/5] =?UTF-8?q?=E6=B8=85=E9=99=A4=E5=A4=9A=E4=BD=99?=
=?UTF-8?q?=E7=A9=BA=E8=A1=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
test:清除多余空行
---
test/UnitTest/Components/TableTest.cs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/test/UnitTest/Components/TableTest.cs b/test/UnitTest/Components/TableTest.cs
index e610b54aae2..e88e00e0eaf 100644
--- a/test/UnitTest/Components/TableTest.cs
+++ b/test/UnitTest/Components/TableTest.cs
@@ -9055,7 +9055,6 @@ public async Task UpdateTableColumnClientStatus_Ok()
});
});
- // 由于启用了客户端持久化 Name 列宽使用 100 而非 80
var table = cut.FindComponent>();
var colGroup = table.Find("colgroup");
Assert.Contains("style=\"width: 120px;\"", colGroup.ToMarkup());
@@ -9073,8 +9072,6 @@ public async Task UpdateTableColumnClientStatus_Ok()
var fixedWidth = cut.FindAll("col")[0].OuterHtml.Contains("width: 200px");
Assert.Equal("fixedWidth:True", $"fixedWidth:{fixedWidth}");
}
-
-
}
[Fact]