James: 本系列为大家介绍如何使用 Blazor 来开发管理后台,有兴趣的朋友欢迎跟着实验,体验 Blazor 开发的高效与乐趣。
本系列目录:
使用 Blazor 开发内部后台(一):认识Blazor
使用 Blazor 开发内部后台(二):了解 Blazor 组件
使用 Blazor 开发内部后台(三):登录
前言
很多后台管理系统会采用侧边栏或上方导航组件来实现导航功能,其实也不复杂,但本文介绍另一种简单直接的选择:仍使用上中下三层布局,单独写一个Home页面用于导航。这样的好处在于Home首页或Layout组件里,不用写嵌套的结构和处理导航组件的点击事件。
Card组件
请读者先自行参考Antd Blazor文档:网格型内嵌卡片。Card本身是非常简单的展示组件,而网格型内嵌卡片,可以方便我们快速搭建一个布局整齐的导航栏。先展示一下页面:
Card的Title用来作为类别的主题,下方的子卡片则展示具体的页面链接。这样每个页面的基础代码如下:
<Card Title="分类主题名称" Bordered="true"><CardGrid Style="width: 25%; text-align: center; padding: 0 5px; background-color: whitesmoke;" Hoverable="true"><a href="/MyUrl1" style="font-size:20px">要导航的页面名1</a></CardGrid><CardGrid Style="width: 25%; text-align: center; padding: 0 5px; background-color: whitesmoke;" Hoverable="true"><a href="/MyUrl2" style="font-size:20px">要导航的页面名2</a></CardGrid>
</Card>
配置和动态化
随着时间的推进,后台管理系统通常会加入越来越多的功能,因此也要求导航栏的内容可以根据配置动态展示。
如果使用上述Card组件,则可以很直观地定义一个Json数据结构:
[{"Title": "用户管理","Items": [{"Name": "列表查询","Route": "/user/list","Disabled": true}]},{"Title": "图书管理","Items": [{"Name": "列表查询","Route": "/book/list"}]},{"Title": "音频管理","Items": [{"Name": "列表查询","Route": "/video/list","Disabled": true}]},{"Title": "新闻管理","Items": [{"Name": "列表查询","Route": "/news/list"}],"Hide": true},{"Title": "统计分析","Items": [{"Name": "登录相关","Route": "/analysis/login","Disabled": false},{"Name": "图书相关","Route": "/analysis/book","Disabled": true},{"Name": "音频相关","Route": "/analysis/video","Disabled": true},{"Name": "新闻相关","Route": "/analysis/news","Disabled": true}]}
]
这里我增加了额外的Hide和Disabled字段,Hide字段决定是否显示某个主题,而Disabled字段决定是否启用某个页面的导航链接(但不隐藏)。对应的Model类如下:
public class HomePageContent{public string Title { get; set; }public HomePageContentItem[] Items { get; set; }public bool Hide { get; set; }}public sealed class HomePageContentItem{public string Name { get; set; }public string Route { get; set; }public bool Disabled { get; set; }}
接着我们要设计如何让Blazor收到这样的配置内容,我们可以让后端以Http接口的方式提供,但我这里介绍一种更直接的办法,供读者参考:
在Blazor项目wwwroot文件夹下创建一个uidata文件夹,在里面再创建一个home文件夹,然后创建一个叫navLinks.json的静态文件用于存储上述的Json数据。
在Blazor项目Services文件夹(没有的话自己创建一个),定义一个接口:
public interface IUserInterfaceDataService{Task<HomePageContent[]> LoadHomePageContentsAsync();}
该接口封装所有类似静态文件的访问请求,符合高内聚低耦合的设计。现在添加一个具体类:
internal class UserInterfaceDataService : IUserInterfaceDataService{private const string Root = "/uidata/";private readonly HttpClient _client;public UserInterfaceDataService(HttpClient client){_client = client;}public Task<HomePageContent[]> LoadHomePageContentsAsync() => GetAsync<HomePageContent>("home/naviLinks.json");private async Task<T[]> GetAsync<T>(string path){var data = await _client.GetFromJsonAsync<T[]>(Root + path);return data;}}
再次提醒:别忘了依赖注入!
之后,我们让home.razor页面在初始化时,先访问静态文件naviLinks.json,然后再根据该文件里的Json数据展示首页内容。在home.razor.cs里,加入代码:
public partial class Home{private HomePageContent[] _contentList = Array.Empty<HomePageContent>();protected async override Task OnInitializedAsync(){_contentList = await UIDataService.LoadHomePageContentsAsync();}}
数据可以获取了,那么如何依赖这样的结构动态生成页面呢?Razor语法的易用性就体现出来了:
@page "/home"
@inject HttpClient Http
@inject IUserInterfaceDataService UIDataService<div style="margin:40px">@foreach (var content in _contentList){@if (!content.Hide){<div style="margin:20px 0"><Card Title=@content.Title Bordered="true">@foreach (var item in content.Items){<CardGrid Style="width: 25%; text-align: center; padding: 0 5px; background-color: whitesmoke;" Hoverable="@(!item.Disabled)">@if (item.Disabled){<span style="font-size:20px;color:dimgray">@item.Name</span>}else{<a href=@item.Route style="font-size:20px">@item.Name</a>}</CardGrid>}</Card></div>}}
</div>
基于@if和@for关键词,可以非常简单地实现HTML代码的动态生成。
现在我们访问首页,Blazor就可以根据静态文件的配置内容动态生成页面了。静态文件的更新不需要重启后端程序,因此首页导航栏的更新对用户和后端来说,都是无感的。有的读者担心浏览器可能会缓存静态文件,导致配置更新不及时——解决办法有很多,例如可以将每次静态文件的请求链接加入一个时间戳的请求参数(.../navLinks.json?t=xxx),或者干脆让用户清除浏览器页面缓存(毕竟只是内部用的后台)。
结束语
下一篇文章准备介绍一下如何使用Antd Blazor组件搭建后台系统中常见的“条件搜索+列表展示”页。不过本月杂事很多,应该要过些日子再更了。
今天是八一建军节,“聚是一团火,散是满天星”,祝现役、退役的所有军人朋友们节日快乐!祝伟大的祖国繁荣昌盛!
欢迎加入 Blazor 中文社区,共同建设热爱的技术社区!
QQ群:1012762441
微信群:JamesYengMVP(加我邀请)