.Net Core Razor动态菜单实现
阅读原文时间:2022年04月28日阅读:2

1.框架

.netcore  版本 yishaadmin开源框架

2.模板

本文模板使用adminlte3.0,文档地址https://adminlte.io/docs/3.0/

3.菜单表

关键字段

id  表主键(当前菜单)

ParentId 父级ID(父级菜单 为0时为顶级菜单,也可能为内容)

MenuUrl 菜单地址(只有页面有地址,本身菜单是空)

MenuType 菜单类型(1是菜单 2是页面 3是按钮)

MenuIcon 图标样式

4.菜单表实体

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YiSha.Util;

namespace YiSha.Entity.SystemManage
{
[Table("SysMenu")]
public class MenuEntity : BaseExtensionEntity
{
[JsonConverter(typeof(StringJsonConverter))]
public long? ParentId { get; set; }

    public string MenuName { get; set; }

    public string MenuIcon { get; set; }

    public string MenuUrl { get; set; }

    public string MenuTarget { get; set; }

    public int? MenuSort { get; set; }

    public int? MenuType { get; set; }

    public int? MenuStatus { get; set; }  
    public string Authorize { get; set; }

    public string Remark { get; set; }

    \[NotMapped\]  
    public string ParentName { get; set; }  
}  

}

  本文是由于框架内置菜单不支持顶级菜单显示为内容,以及菜单最多只支持三级菜单的问题,故进行了调整。

1.实现思路

  下图1区域渲染为菜单,菜单通过点击URL将内容填充到2区域。

2.编码

2.1  建立渲染内容填充方法

将传进来的url通过ajax调用最终渲染到内容区域(id为#Content的Div中),其中beforeSend方法显示Loadding 可根据需要自行调整。url为{area:exists}/{controller=Home}/{action=Index}以及{controller=Home}/{action=Index}根据框架配置填写至菜单

function LoadContent(url) {
if (url == null || url == "")
return;

    $.ajax({  
        url: url,  
        beforeSend: function (XHR) {  
            $.blockUI({ message: '<div class="loaderbox"><div class="loading-activity"></div> '   
             + "加载中..." + '</div>', css: { border: "none", backgroundColor: 'transparent' } });  
        },  
        success: function (data) {  
            $("#Content").html(data);  
            setTimeout(function () { $.unblockUI(); }, 100);  
        },  
        error: function (data, status, e) {  
            $("#Content").html("页面加载失败," + data.status + "," + url + "<br />" + data.responseText);  
            setTimeout(function () { $.unblockUI(); }, 100);  
        }  
    });  

}

2.2  建立分部视图

通过建立分部视图MenuTree,循环传入的菜单,初始化时先获取父级ID(ParentId)为0并且类别(MenuType)不为按钮的菜单集合进行循环,根据menuEntity.MenuUrl判断是否为页面,如果依然为菜单则使用Html.PartialAsync("MenuTree")调用自身来实现递归,第二次则根据ViewData["Menu"]传入的当前id作为父级id来寻找子集,直到寻找到最后的层级。

@using System.Collections.Generic
@using YiSha.Entity.SystemManage;
@model List

@{
if (Model.Any())
{
long id = 0L;
var menu = ViewData["Menu"] as MenuEntity;
if (menu != null)
id = menu.Id.Value;

    @foreach (var menuEntity in Model.Where(o => o.ParentId == id && o.MenuType != (int)MenuTypeEnum.Button))  
    {  
        var icno = string.IsNullOrEmpty(menuEntity.MenuIcon) ? "fa fa-comment" : menuEntity.MenuIcon;  
        @if (!string.IsNullOrEmpty(menuEntity.MenuUrl))  
        {  
           <li class="nav-item">  
               <a href="#" class="nav-link" onclick="LoadContent('@menuEntity.MenuUrl')">  
                   <i class="nav-icon @icno"></i>  
                   <p>  
                       @menuEntity.MenuName  
                   </p>  
               </a>  
           </li>  
        }  
        else  
        {  
            ViewData\["Menu"\] = menuEntity;  
            <li class="nav-item">  
                <a href="#" class="nav-link">  
                <i class="nav-icon @icno"></i>  
                <p>  
                    @menuEntity.MenuName  
                    <i class="fas fa-angle-left right"></i>  
                </p>  
                </a>  
                <ul class="nav nav-treeview">  
                     @await Html.PartialAsync("MenuTree",  
                     Model,new ViewDataDictionary(ViewData))  
                </ul>  
           </li>  
        }  
     }  
}  

}

3.调用分布视图

 <aside class="main-sidebar sidebar-dark-primary elevation-4" style="width:200px;position:fixed">  
        <!-- Brand Logo -->

        <!-- Sidebar -->  
        <div class="sidebar">

            <!-- Sidebar Menu -->  
            <nav class="mt-2">  
                <ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">  
                    <!-- Add icons to the links using the .nav-icon class  
with font-awesome or any other icon font library -->

                    <li class="nav-header" style="font-size:1.0rem">  
                        <img src="~/yisha/img/logo1.png" style="width: 30px; height: 30px; " />  
                        任务管理系统  
                    </li>

                    @await Html.PartialAsync("MenuTree", Model)  
                </ul>  
            </nav>  
            <!-- /.sidebar-menu -->  
        </div>  
        <!-- /.sidebar -->  
    </aside>

    <!-- Content Wrapper. Contains page content -->  
    <div class="content-wrapper" id="mainhead">  
        <div id="Content">

        </div>  
    </div>