MAUI加Blazor做一个跨平台的记账APP(七)组件
实际上每个页面都可以是一个组件或者叫子模块。加上了路由和代码逻辑后,使其成为了一个相对独立的页面。
但我们有时候也需要自定义一些可以复用的组件,嵌入到特定的几个页面里,这里记录一下。
比如我现在想在账户总览页面上增加一个小区域,用来展示一旦请求失败或者数据缺失时的错误信息。发现其他页面也会需要这个区域,于是决定把错误提示的区域做成一个可以复用的组件。
首先在pages目录下增加ErrorComponent.razor文件,展示一行大字和一行红色的小字,小字是具体的错误信息,错误信息可以通过传递参数的方式来展示不同的文本,也设置了默认值为'未知错误':
<h3>出错啦</h3>
<span style="color: red;">@ErrorMessage</span>
@code {
[Parameter]
public string ErrorMessage { get; set; }
protected override void OnParametersSet()
{
if (string.IsNullOrWhiteSpace(ErrorMessage))
{
ErrorMessage = "未知错误";
}
}
}
接着直接在其他页面里作为标签一样使用就可以了。和vue之类的差不多,不过更方便一点的是都不需要导入了,直接用。
@page "/accounts"
<PageTitle>账户总览</PageTitle>
<h1>资金账户汇总</h1>
@if (@hasError)
{
<hr/>
<ErrorComponent></ErrorComponent>
<ErrorComponent ErrorMessage="this is a customized error message"></ErrorComponent>
}
这里有一个hasError的字段决定是否展示这个区域,改一点对应的razor.cs文件,设置为true就显示了。当然实际需要根据异常捕获来改这个值和改实际的错误信息。
namespace accountingMAUIBlazor.Pages;
public partial class Accounts
{
public bool hasError = true;
}
现在要在其他页面里也继续加这个组件,然后就觉得有点麻烦,我一定要在所有需要的页面都添加一次吗?有没有可能在一个统一的地方加了,其他地方就只管传值就行了。
然后试了下,有办法。
我们可以加到MainLayout.razor文件里,这个文件里就是定义统一布局的,在里面我们能看到NavMenu还有Body。打算加在Body之后。
首先我们需要用到<CascadingValue Value="this"> //.... </CascadingValue>,将页面内容包裹起来。
于是MainLayout.razor的内容就变成了:
@using accountingMAUIBlazor.Pages;
@inherits LayoutComponentBase
<div class="page">
<CascadingValue Value="this">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<article class="content px-4">
@Body
@if (@hasErrorGlobal)
{
<hr />
<ErrorComponent></ErrorComponent>
<ErrorComponent ErrorMessage=@customizedError></ErrorComponent>
}
</article>
</main>
</CascadingValue>
</div>
@code {
public string customizedError = "this is a customized error message";
private bool _hasErrorGlobal;
public bool hasErrorGlobal
{
get => _hasErrorGlobal;
set
{
if (_hasErrorGlobal != value)
{
_hasErrorGlobal = value;
InvokeAsync(() => StateHasChanged());
}
}
}
protected override void OnParametersSet()
{
_hasErrorGlobal = false;
}
}
这里OnParametersSet会在每一次加载时将hasErrorGlobal给恢复为false,以免一个页面出错,所有的都在提示错误。
接着其他页面就不需要指定这个组件标签了,只需要在页面代码里改一下字段的值就可以了。
accounts.razor里去掉ErrorComponent:
@page "/accounts"
<PageTitle>账户总览</PageTitle>
<h1>资金账户汇总</h1>
accounts.razor.cs里需要通过CascadingParameter来对应到MainLayout,这里还是直接在页面初始化时让其显示错误区域,之后根据异常捕获来更改:
using accountingMAUIBlazor.Shared;
using Microsoft.AspNetCore.Components;
namespace accountingMAUIBlazor.Pages;
public partial class Accounts
{
[CascadingParameter]
public MainLayout Layout { get; set; }
protected override void OnInitialized()
{
Layout.hasErrorGlobal = true;
}
}
效果和上图一样,这样会更简便一点。