父子组件传值
在 Blazor
中,组件之间的通信可以通过 [Parameter]
参数和 EventCallback<T>
事件回调实现。下面分别给出 父组件传递值给子组件 和 子组件传递值给父组件 的简单示例。
1.1 父组件传递值给子组件
步骤:
- 在子组件中定义
public
属性,并使用[Parameter]
特性标记。 - 在父组件中通过绑定属性将值传递给子组件。
示例代码:
子组件 ChildComponent.razor
<h3>子组件收到的值: @Message</h3>@code {[Parameter]public string Message { get; set; }
}
父组件 ParentComponent.razor
<ChildComponent Message="@message" />@code {private string message = "Hello from parent!";
}
1.2 子组件传递值给父组件
步骤:
- 使用
EventCallback<T>
实现子组件向父组件传值。 - 子组件触发事件并携带数据,父组件监听该事件并处理数据。
示例代码:
子组件 ChildComponent.razor
<button @onclick="SendMessage">发送消息给父组件</button>@code {[Parameter]public EventCallback<string> OnMessageSent { get; set; }private async Task SendMessage(){await OnMessageSent.InvokeAsync("这是来自子组件的消息");}
}
父组件 ParentComponent.razor
<ChildComponent OnMessageSent="HandleMessage" />
<p>收到子组件的消息: @receivedMessage</p>@code {private string receivedMessage;private void HandleMessage(string message){receivedMessage = message;}
}
1.3 总结
通信方向 | 实现方式 |
---|---|
父组件 → 子组件 | 使用 [Parameter] 传递属性值 |
子组件 → 父组件 | 使用 EventCallback<T> 触发事件 |
这种方式可以满足大多数 Blazor
组件间的基本通信需求。
级联组件传值
在 Blazor
中,级联传值(Cascading Communication) 可以通过以下几种方式实现:
- 使用
CascadingParameter
实现层级组件传值 - 使用
CascadingValue
组件包裹子树,并向下传递数据
下面是一个 三层级组件传值的完整示例(父 → 子 → 孙)。
2.1 使用 CascadingValue
和 CascadingParameter
示例结构
ParentComponent.razor
└── ChildComponent.razor└── GrandChildComponent.razor
Ⅰ. 父组件:ParentComponent.razor
@page "/parent"<CascadingValue Value="@message"><ChildComponent />
</CascadingValue>@code {private string message = "来自父组件的消息";
}
Ⅱ. 子组件:ChildComponent.razor
<h4>子组件收到消息: @cascadeMessage</h4>
<GrandChildComponent />@code {[CascadingParameter]public string cascadeMessage { get; set; }
}
Ⅲ. 孙组件:GrandChildComponent.razor
<h5>孙组件收到消息: @cascadeMessage</h5>@code {[CascadingParameter]public string cascadeMessage { get; set; }
}
2.2 运行效果
访问 /parent
路由后,页面将显示如下内容:
子组件收到消息: 来自父组件的消息
孙组件收到消息: 来自父组件的消息
说明:
CascadingValue
将值从父组件广播给其所有嵌套子组件。- 所有子组件通过
[CascadingParameter]
接收值,无需手动逐层传递。
2.3 注意事项
注意点 | 说明 |
---|---|
类型匹配 | CascadingValue 的类型必须与接收组件的 CascadingParameter 类型一致 |
多个值 | 可以使用多个 CascadingValue 包裹不同值,或使用对象封装多个字段 |
性能影响 | 不建议过度使用级联参数,避免造成上下文污染和性能问题 |
2.4 进阶用法:传递对象而非基本类型
<CascadingValue Value="@userContext"><ChildComponent />
</CascadingValue>@code {private UserContext userContext = new UserContext { Name = "Alice", Role = "Admin" };
}public class UserContext {public string Name { get; set; }public string Role { get; set; }
}
子组件中接收:
[CascadingParameter]
public UserContext userContext { get; set; }
如需更复杂的通信(如跨层级双向绑定),可以结合 EventCallback
或使用状态管理库(如 Fluxor
)。
更复杂的通信
在 Blazor
中,当组件层级较深或需要实现 跨层级双向绑定通信 时,推荐使用以下两种方式:
✅ 方案一:结合 EventCallback
实现跨层级通信
场景说明:
- 组件层级嵌套较深(如
父 → 子 → 孙
)。 - 需要从最内层子组件向顶层组件传递数据,并同步更新状态。
示例结构:
ParentComponent.razor
└── ChildComponent.razor└── GrandChildComponent.razor
1. 父组件:ParentComponent.razor
@page "/parent"<h3>父组件显示的值: @sharedValue</h3><ChildComponent OnValueChanged="UpdateValue" />@code {private string sharedValue = "初始值";private void UpdateValue(string newValue){sharedValue = newValue;}
}
2. 子组件:ChildComponent.razor
<GrandChildComponent OnValueChanged="OnValueChanged" />@code {[Parameter]public EventCallback<string> OnValueChanged { get; set; }
}
3. 孙组件:GrandChildComponent.razor
<input @bind="inputValue" />
<button @onclick="SendValueToParent">发送到父组件</button>@code {private string inputValue = "默认输入";[Parameter]public EventCallback<string> OnValueChanged { get; set; }private async Task SendValueToParent(){await OnValueChanged.InvokeAsync(inputValue);}
}
运行效果:
- 在孙组件中修改输入框内容并点击按钮;
- 消息会逐级上传至父组件;
- 父组件中的
sharedValue
被更新并重新渲染。
✅ 方案二:使用状态管理库 Fluxor 实现全局共享状态(推荐)
优势:
- 避免层层传递参数和事件回调;
- 实现组件间真正的“双向绑定”;
- 支持集中管理应用状态,提升可维护性。
安装 Fluxor
通过 NuGet 安装:
dotnet add package Fluxor --version 6.6.0
注册服务(在 Program.cs
中):
builder.Services.AddFluxor(options =>options.ScanAssemblies(typeof(Program).Assembly));
1. 创建 State 类:CounterState.cs
public class CounterState(int count)
{public int Count { get; } = count;
}
2. 创建 Feature 和 Reducer:CounterFeature.cs
public class CounterFeature : Feature<CounterState>
{public override string GetName() => "Counter";public override CounterState GetInitialState() => new(0);
}public record IncrementAction();
public record DecrementAction();public class CounterReducer
{[ReducerMethod]public static CounterState Increment(CounterState state, IncrementAction action) =>new(state.Count + 1);[ReducerMethod]public static CounterState Decrement(CounterState state, DecrementAction action) =>new(state.Count - 1);
}
3. 创建 Store 并使用(任意组件中)
使用 Store 的组件示例:CounterComponent.razor
@inject IStore store;
@inject IDispatcher dispatcher;<p>当前计数: @counterState.Value.Count</p>
<button @onclick="Increment">+1</button>
<button @onclick="Decrement">-1</button>@code {private IState<CounterState> counterState;protected override void OnInitialized(){counterState = store.GetState<CounterState>();}private void Increment() => dispatcher.Dispatch(new IncrementAction());private void Decrement() => dispatcher.Dispatch(new DecrementAction());
}
运行效果:
- 多个组件都可以访问和修改同一个
Count
值; - 所有监听该状态的组件都会自动刷新;
- 实现了真正的跨层级、双向绑定通信。
🧠 总结对比
方式 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
EventCallback | 层级不深 / 单向/双向传值 | 简单直接 | 层级多时繁琐 |
CascadingParameter | 同一树状结构下传值 | 快速广播 | 只能读取,不能双向绑定 |
Fluxor | 全局状态共享 / 复杂交互 | 状态统一管理,解耦组件 | 初期配置复杂 |
✅ 推荐实践
- 小型项目:使用
EventCallback
&CascadingParameter
。 - 中大型项目或需要跨组件共享状态:优先使用
Fluxor
。 - 更高级需求可考虑配合
TimeWarp.State
或MediatR
。
说明:
- Blazor-State 已更名为 TimeWarp.State
相关 nuget
包资源:
Blazor-State
,https://www.nuget.org/packages/Blazor-State/11.0.0-beta.36
TimeWarp.State
,https://www.nuget.org/packages/TimeWarp.State/
MediatR
,https://www.nuget.org/packages/MediatR