Blazor动态组件点击事件向父/祖父组件传递的实现方案咨询
Blazor DataTable组件排序功能实现方案
核心思路
通过组件间回调参数传递实现事件向上冒泡:
- DataTableSort子组件接收父组件DataTableColumn传递的点击回调
- DataTableColumn将自身的列标识(对应数据属性名)通过回调传递给DataTable祖父组件
- DataTable维护排序状态(当前排序列、升降序)并执行排序逻辑,更新表格数据
具体修改步骤
1. 给DataTable组件添加排序状态与逻辑
修改DataTable.razor:
@typeparam TRowData <CascadingValue IsFixed="true" Value="this">@ChildContent</CascadingValue> <table> <thead> <tr> @foreach (var column in columns) { @column.HeaderTemplate; } </tr> </thead> <tbody> @if (Items != null) { var sortedItems = GetSortedItems(); foreach (var item in sortedItems) { <tr @key="item"> @foreach (var column in columns) { @column.CellTemplate(item); } </tr> } } </tbody> </table> @code { [Parameter] public ICollection<TRowData> Items { get; set; } [Parameter] public RenderFragment ChildContent { get; set; } private readonly List<DataTableColumn<TRowData>> columns = new(); private string _currentSortColumn; private bool _isAscending = true; internal void AddColumn(DataTableColumn<TRowData> column) { columns.Add(column); } // 处理排序请求 internal void RequestSort(string columnName) { if (_currentSortColumn == columnName) { // 同一列点击,切换升降序 _isAscending = !_isAscending; } else { // 新列排序,默认升序 _currentSortColumn = columnName; _isAscending = true; } StateHasChanged(); // 更新UI } // 获取排序后的数据集 private IEnumerable<TRowData> GetSortedItems() { if (Items == null || string.IsNullOrEmpty(_currentSortColumn)) return Items; // 通过反射实现基础排序,可后续用Expression优化性能 var property = typeof(TRowData).GetProperty(_currentSortColumn); if (property == null) return Items; return _isAscending ? Items.OrderBy(item => property.GetValue(item)) : Items.OrderByDescending(item => property.GetValue(item)); } protected override void OnAfterRender(bool firstRender) { if (firstRender) { StateHasChanged(); } } }
2. 修改DataTableColumn组件,传递排序回调
更新DataTableColumn.razor中的HeaderTemplate,给DataTableSort绑定回调并传递列标识:
@typeparam TRowData @using System.Linq.Expressions @code { [CascadingParameter] public DataTable<TRowData> Owner { get; set; } [Parameter] public string Title { get; set; } [Parameter] public bool Sortable { get; set; } = false; // 默认不可排序 [Parameter] public string Format { get; set; } [Parameter] public Expression<Func<TRowData, object>> Expression { get; set; } [Parameter] public RenderFragment<TRowData> ChildContent { get; set; } private RenderFragment<TRowData> cellTemplate; private RenderFragment headerTemplate; private Func<TRowData, object> compiledExpression; private Expression lastCompiledExpression; private string _columnName; internal RenderFragment HeaderTemplate { get { return headerTemplate ??= (builder => { var title = Title ?? (Expression != null ? GetMemberName(Expression) : string.Empty); _columnName = Expression != null ? GetMemberName(Expression) : null; builder.OpenElement(0, "th"); builder.AddContent(1, title); if (Sortable && !string.IsNullOrEmpty(_columnName)) { // 渲染排序按钮并绑定回调 builder.OpenComponent<DataTableSort>(1); builder.AddAttribute(2, "OnSortClicked", EventCallback.Factory.Create(this, () => Owner.RequestSort(_columnName))); builder.AddAttribute(3, "IsAscending", _currentSortColumn == _columnName && Owner._isAscending); builder.CloseComponent(); } builder.CloseElement(); }); } } // 其余原有代码保持不变... private static string GetMemberName<T>(Expression<T> expression) { return expression.Body switch { MemberExpression m => m.Member.Name, UnaryExpression u when u.Operand is MemberExpression m => m.Member.Name, _ => throw new NotSupportedException("不支持该类型的表达式") }; } }
3. 修改DataTableSort组件,接收并触发回调
更新DataTableSort.razor,添加参数接收回调与排序状态:
<button @onclick="HandleSortClicked" style="margin-left:8px"> @(IsAscending ? "↑" : "↓") </button> @code { // 接收父组件传递的排序回调 [Parameter] public EventCallback OnSortClicked { get; set; } // 接收当前排序状态,用于显示箭头方向 [Parameter] public bool IsAscending { get; set; } = true; private async Task HandleSortClicked() { await OnSortClicked.InvokeAsync(); } }
4. 在页面中启用列排序
修改Page.razor,给需要排序的列添加Sortable="true":
<DataTable Items="users"> <DataTableColumn TRowData="User" Expression="u => u.Id" Sortable="true"/> <DataTableColumn TRowData="User" Expression="u => u.Username" Sortable="true" /> <DataTableColumn TRowData="User" Expression="u => u.DateOfBirth" Sortable="true" /> <DataTableColumn TRowData="User"><div>Column B</div></DataTableColumn> </DataTable>
可选优化点
- 用预编译Expression替代反射排序,提升大数据量场景下的性能
- 支持多列排序:维护排序列优先级列表,实现多维度排序
- 优化排序按钮样式,增强交互反馈
内容的提问来源于stack exchange,提问作者Musaffar Patel
相关产品推荐
相关产品推荐

