我们常用路由传递页面变量值,如:Navigate.NavigateTo("/xxxx/value"),这个value会暴露在浏览器Url路由中,不太安全。在同一个父级组件中,我们可以用 CascadingValue 来传递给各子组件,甚至孙组件,也可实现回调,使用EventCallback回调改变父级组件的这变量值。在同一个页面中的各父子组件传递变量,有用,却不是很方便。如果子组件1用户操作后,转到组件2,这时我们不想再显示组件1,又要处理不显示组件1的动作,再处理显示组件2的动作,真的很麻烦。所以是否有办法考虑创建页面级的变量呢?页面变量其实就是Layout母版页中的Body能接受的变量,但是我们在编写组件页的时候,它不能简单地实现回调方法,编写的EventCallback 回调方法无法简单地 ="@某个父级方法",只要解决这个难题,问题就迎刃而解了。
首先,这个页面级变量是啥?我觉得吧,就是个Id值,一般是int类型,供各页面组件使用来获取数据库的相应数据,这个非常有用,它能不再显示在浏览器Url路由中,更加安全。其次, ="@某个父级方法",就是创建一个回调代理,查看EventCallback的从元数据中有public EventCallback(IHandleEvent? receiver, MulticastDelegate? @delegate)的创建方法,如何使用考验我们的理解能力。
下面就是代码了:
@code {
public int IdValue { get; set; } = 188;//初始值测试用
public EventCallback<int> OnIdValueChanged;
public void OnIdValueChangedHandle(int id)
{
IdValue = id;
}
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
OnIdValueChanged = new EventCallback<int>(this, @OnIdValueChangedHandle);
}
}
然后就是 CascadingValue 出场了:
<CascadingValue TValue="int" IsFixed="false" Value="@IdValue" Name="Id">
<CascadingValue TValue="EventCallback<int>" Value="OnIdValueChanged" Name="OnIdValueChanged">
<article class="content px-4">
@Body
</article>
</CascadingValue>
</CascadingValue>
CascadingValue 支持嵌套,这里要把变量值和回调事件都传递下去。
最后是在各页面组件中的接收及回调处理代码:
@code {
[CascadingParameter(Name = "Id")]
protected int Id { get; set; }
[CascadingParameter(Name = "OnIdValueChanged")]
protected EventCallback<int> OnIdValueChanged { get; set; }
private async Task ChangeIdValue() //(int id)
{
Id++;//Id=id;
await OnIdValueChanged.InvokeAsync(Id);
Navigate.NavigateTo("/xxxx"); //这里就不用加上路由value 来传递值了
}
}
我们来测试下:
//Counter.razor
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<h3>IdValue : @Id</h3>
<button class="btn btn-primary" @onclick="ChangeIdValue">ChangeIdValue</button>
<IdValueChange/>
@code {
[CascadingParameter(Name = "Id")]
protected int Id { get; set; }
[CascadingParameter(Name = "OnIdValueChanged")]
protected EventCallback<int> OnIdValueChanged { get; set; }
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
private async Task ChangeIdValue()
{
Id++;
await OnIdValueChanged.InvokeAsync(Id);
}
}
//IdValueChange.razor
<h3>IdValueChange</h3>
<h3>IdNewValue : @Id</h3>
@code {
[CascadingParameter(Name = "Id")]
protected int Id { get; set; }
}
虽然测试时放在一个页面,但你们也看到了,2个子组件是没有联系的,后面的组件可以设计成页面组件。
效果图如下:
我们能够看到值都能变了。