Blazor 中处理空数据状态的关键,不是堆砌条件判断,而是把“空”当成一种可预期、可复用、可组合的状态来设计。
用独立组件封装空状态逻辑
把空状态(如无数据、加载中、加载失败)抽成一个通用组件,比如
EmptyState.razor,接收参数控制显示内容和行为: type:枚举值(
None、
Loading、
NoData、
Error) message:自定义提示文案(可选) onRetry:点击重试时触发的回调(仅 error 状态需要)
这样在业务组件里只需写:
<emptystate type="@dataState" onretry="LoadData"></emptystate>
逻辑清晰,样式和交互统一,后续加动画或埋点也只改一处。
配合 async
+ Task
自然表达加载流程
避免手动维护
IsLoading、
HasData、
ErrorMessage多个布尔/字符串字段。推荐用一个状态容器封装:
public class DataResult<T>
{
public bool IsLoading { get; set; }
public T? Value { get; set; }
public string? Error { get; set; }
}在页面中直接绑定:
@if (result.IsLoading) { <p>加载中...</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/ai/1915" title="Summarizer"><img
src="https://www.herecours.com/d/file/efpub/2026/21-21/20260221140337179519.jpg" alt="Summarizer" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/ai/1915" title="Summarizer">Summarizer</a>
<p>基于 AI 的文本段落摘要生成器</p>
</div>
<a href="/ai/1915" title="Summarizer" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div> }<br>
else if (result.Error != null) { <EmptyState Type="Error" ... /> }<br>
else if (result.Value is null || !result.Value.Any()) { <EmptyState Type="NoData" /> }<br>
else { /* 渲染列表 */ }
用 RenderFragment
让空状态支持定制化内容
空状态组件别写死图标和按钮。通过
RenderFragment参数允许父组件传入任意 UI:
<EmptyState Type="@state">
<NoDataTemplate>
<div class="empty-icon">?</div>
<p>暂无文件,点击上传</p>
<button @onclick="OpenUpload">上传文件</button>
</NoDataTemplate>
</EmptyState>组件内部用
@ChildContent或命名模板(
[Parameter] public RenderFragment? NoDataTemplate { get; set; })接收,灵活又不侵入业务逻辑。
服务端分页场景下,区分“真空”和“已到底”
列表滚动加载时,“空数据”可能是第一页没数据(真空),也可能是后面没更多了(已到底)。建议后端返回分页元信息(
HasNextPage、
TotalCount),前端据此决定是否显示「暂无更多」提示,而不是统一用“暂无数据”。
例如:
-
TotalCount == 0→ 显示“列表为空,快去添加吧”
-
HasNextPage == false && items.Count == 0→ 不显示任何空状态(说明是初始加载完成且无数据)
-
HasNextPage == false && items.Count > 0→ 滚动到底,显示“没有更多了”
基本上就这些。核心是把空状态从“分支判断”变成“状态建模”,组件化、参数化、语义化,代码就自然干净了。
