本文是关于为ASP.NET Core创建动态菜单系统。
在开发新的Web应用程序时,我们想要添加一个基于当前路由和参数动态生成的菜单组件。
我最初研究了ASP.NET Core中partials的概念,虽然这些对于重用静态标记非常有用,但它们对于构建动态菜单等动态的数据驱动内容并不是那么好。
如果您的需求是重用动态和/或数据驱动的内容,那么正确的设计方法是使用ViewComponent。来自Microsoft文档
在查看Partial Views和View Components之后,我发现ViewComponents不必依赖已存在的数据。例如,您可以简单地对服务器端方法进行异步调用,如下所示:
@await Component.InvokeAsync("MenuItems", 1234)
根据Microsoft文档,视图组件与部分视图类似,但是视图组件更加强大。视图组件不一定使用模型绑定,仅取决于调用时提供的数据。视图组件:
视图组件适用于任何具有可重用渲染逻辑的位置,这些逻辑对于局部视图来说过于复杂,例如:
所以现在,我们的菜单树结构由ViewComponent处理。构建用户指定菜单的所有业务逻辑都包含在ViewComponent中,ViewComponent返回菜单树结构。然后由调用ViewComponent的Razor页面显示。当你调用视图组件方法时,不必传递参数,也不必传递视图模型。但是,对于Partials,您需要在要渲染部分视图的时传递数据(视图模型),因此您需要事先准备好数据,使其与现有视图紧密耦合。
还有许多其他好处,例如:
这是View Component本身:
namespace WebApplication1.Controllers
{
public class MenuViewComponent : ViewComponent
{
private readonly MenuHelper _cbaMenuHelper = new MenuHelper();
public async Task InvokeAsync(int testId)
{
//testId is optional, and can be passed in when you call InvokeAsync
//Parse current URL to determine which menu item to highlight:
string baseUrl = Request.Scheme + "://" + Request.Host.Value;
var httpRequestFeature = Request.HttpContext.Features.Get();
var uri = httpRequestFeature.RawTarget;
var id = HttpContext.Request.Query["id"].ToString(); //Parse Query String
var menuItems = await _cbaMenuHelper.GetAllMenuItems(baseUrl + uri, id); //Can pass in testId here if required.
return View("_MenuPartial", _cbaMenuHelper.GetMenu(menuItems, null));
}
}
}
该ViewComponent调用其他方法来实际生成菜单。在这种情况下,它只是一个Parent - >child映射菜单对象列表,以下代码在此供您参考:
public class Menu
{
public Guid ID { get; set; }
public Guid? ParentID { get; set; }
public string Content { get; set; }
public string IconClass { get; set; }
public string Url { get; set; }
public string SelectedStyle { get; set; } // If you want a style vs a class;
public string SelectedClass { get; set; }
public string OnClick { get; set; }
public long Order { get; set; }
}
一旦你获得菜单项的“分层”列表后,只需将其返回到InvokeAsync()方法内显示的视图中即可。在这种情况下,视图只是根据菜单记录中的父子关系递归显示菜单项:
@foreach (var menu in Model)
{
if (menu.Children.Any())
{
@menu.Content
}
else
{
@{
if (string.IsNullOrEmpty(menu.Url)) //Add either onclick event or href.
{
@menu.Content
}
else
{
@menu.Content
}
}
}
}
这将返回包装在一个实例中IViewComponentResult,该实例是从ViewComponent返回的受支持的结果类型之一。
这是从布局页面调用ViewComponent的调用,如下所示:
@await Component.InvokeAsync("Menu", new { cbaId = ViewBag.Id })
在这种情况下我使用了ViewBag将ID传递给ViewComponent,因此有一些显示内容的上下文。您还可以在ViewComponent中查看我检索当前Route,并使用它以及上面的Id来确定要加载的菜单项。
最终结果如下:
您可以看到排序是正确的,并且使用了Font Awesome图标,一个漂亮的可折叠菜单就这样创建了。单击“新建”按钮可以运行自定义Javascript,最有可能创建一些内容:
其余的项是路径Url,都是从MenuHelper类创建的。我使用基本的ASP.NET Core应用程序作为起点并围绕它“包装”我的菜单组件。
文章中的源代码可在以下地址中找到:https://github.com/IntrinsicInnovation/CoreMenuBuilder
我很快就创建了整个动态菜单系统。并且,它基本上独立于系统中的其他视图和部分视图。只需将我的所有代码剪切并粘贴到您的应用程序中,即可重复使用。这是一个现实世界的例子,解决了现代应用程序开发的非常现实的问题。拥有这样的独立易于测试的模块可确保您的应用程序不太可能在生产环境中引发问题。
原文地址:https://www.codeproject.com/Articles/1271364/Creating-a-Side-Menu-for-ASP-NET-Core-using-a-View