今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了:

首先创建节点类(我给它取名:AdminUserTree):

 /// <summary>
/// 无限极节点类
/// </summary>
public class AdminUserTree
{
/// <summary>
/// 节点信息
/// </summary>
public int NodeID { get; set; }
/// <summary>
/// 节点名称
/// </summary>
public string NodeName { get; set; }
/// <summary>
/// 父节点ID
/// </summary>
public int ParentID { get; set; }
/// <summary>
/// 对应的链接地址
/// </summary>
public string Url { get; set; }
public int? PermissionID { get; set; }
public int? OrderID { get; set; }
public string Location { get; set; }
public string comment { get; set; }
public string ImageUrl { get; set; }
/// <summary>
/// 层级
/// </summary>
public int level { get; set; }
/// <summary>
/// 子节点数目(很重要)
/// </summary>
public int childNumberl { get; set; } /// <summary>
/// 子节点 (子节点是一个List)这种用法叫什么?
/// </summary>
public List<AdminUserTree> childNode { get; set; }
}

为无限极分类填充数据,由于考虑到示来管理后台每个页面都会调用到,这里我为控制器创建了一个基类方法

 /// <summary>
/// 管理页面基类(MVC Controller)
/// </summary>
public class AdminBase: Controller
{
/// <summary>
/// EF数据访问配置
/// </summary>
private readonly ApplicationDbContext _basecontext; /// <summary>
/// 管理菜单 这里是基数,声明为属性以便控制器里面可以用到
/// </summary>
public AdminUserTree leftMenu { get; set; } public AdminBase(ApplicationDbContext context)
{
_basecontext = context;
//初始化无限极分类管理菜单
buildtree();
} /// <summary>
/// 建立无限极节点树-管理菜单
/// </summary>
public void buildtree()
{
AdminUserTree result = new AdminUserTree();
//初始化一个节点做为根节点
result.NodeID = ;
result.NodeName= "管理员菜单";
result.Url = "";
result.ParentID = -;
result.Location = "";
result.OrderID = ;
result.comment = "";
result.ImageUrl = "";
result.PermissionID = ;
result.level = ;
result.childNumberl = ;
//把根节点传递给递归方法去创建子节点
result.childNode=BuildMenuTree(result, -);
leftMenu = result;
} /// <summary>
/// 递归创建子节点方法
/// </summary>
/// <param name="node">要为其分配子节点的父级节点</param>
/// <param name="levelID">层级关系</param>
/// <returns></returns>
protected List<AdminUserTree> BuildMenuTree(AdminUserTree node, int levelID)
{
var listtree = _basecontext.Admintree; //从数据库中取出node节点的全部子节点 条件:m.ParentID==node.NodeID
List<AdminUserTree> lt = listtree.Where(m => m.ParentID==node.NodeID )
.Select(m=>new AdminUserTree() {
NodeID =m.NodeID
,NodeName=m.NodeName
,Url=m.Url
,ParentID=m.ParentID
,Location=m.Location
,OrderID=m.OrderID
,comment=m.comment
,ImageUrl=m.ImageUrl
,PermissionID=m.PermissionID})
.ToList(); if (lt != null)
{
//节点深度
node.level = levelID + ;
//子节点数量,便于前端递归输出时调用
node.childNumberl = lt.Count;
for (int i = ; i < lt.Count; i++)
{
//递归调用创建子节点
lt[i].childNode = BuildMenuTree(lt[i], node.level);
}
return lt; }
else {
return null;
} } }

控制器(Controller)继承及调用代码:

   public class AdminTreeController : AdminBase
{
private readonly ApplicationDbContext _context; public AdminTreeController(ApplicationDbContext context):base(context)
{
_context = context;
} // GET: AdminTree
public async Task<IActionResult> Index(int id=)
{
var treelist = _context.Admintree;
var pageOption = new WeiPagerOption
{
CurrentPage = id,
PageSize = ,
Total = await treelist.CountAsync(),
RouteUrl = "/Admintree/Index",
pageNumStep =
}; //分页参数
ViewBag.PagerOption = pageOption; //无限极分类菜单绑定在这里
ViewBag.mainMenu = leftMenu; //返回主要数据
return View(await treelist.OrderByDescending(b => b.OrderID).Skip((pageOption.CurrentPage - ) * pageOption.PageSize).Take(pageOption.PageSize).ToListAsync());
}

View层代码:

 @model IEnumerable<Hxwei.WebWQSF.Models.AdminTreeModel>
@using Hxwei.WebWQSF;
@using Hxwei.WebWQSF.Controllers;
@using System.Text;
@{
ViewData["Title"] = "菜单管理";
}
@functions
{
public string getAdminMenu(AdminUserTree node)
{
StringBuilder sb = new StringBuilder(); List<AdminUserTree> ls = node.childNode;
if(ls.Count>)
{
//遍历每个子节点以输出,这里用到了排序ls.OrderBy(m => m.OrderID)
foreach (var r in ls.OrderBy(m => m.OrderID))
{
if (r.childNumberl > )
{
//当存在子菜单时的方法,这里会有递归调用
sb.Append("<div class=\"btn-group\">");
sb.Append("<button type=\"button\" class=\"btn btn-default dropdown-toggle\" data-toggle=\"dropdown\">");
sb.Append(r.NodeName);
sb.Append("<span class=\"caret\"></span>");
sb.Append("</button>");
sb.Append("<ul class=\"dropdown-menu\" role=\"menu\">");
//递归调用
sb.Append(getAdminMenu(r));
sb.Append("</ul>");
sb.Append("</div>"); }
else
{
//当不存在子菜单时输出
string ntext = string.Format("<li><a href=\"{0}\">{1}</a></li>",r.Url,r.NodeName);
sb.Append(ntext); }
} } return sb.ToString();
}
}
<div class="row">
<div class="col-md-3 navbar-inverse">
<div class="btn-group-vertical col-md-10"> <button type="button" class="btn btn-default">@ViewBag.mainMenu.NodeName</button>
@Html.Raw(getAdminMenu(ViewBag.mainMenu)); </div> </div>
<div class="col-md-9">
<h2>Index</h2> <p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.NodeName)
</th>
<th>
@Html.DisplayNameFor(model => model.ParentPath)
</th>
<th>
@Html.DisplayNameFor(model => model.OrderID)
</th>
<th>
@Html.DisplayNameFor(model => model.Url)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.NodeName)
</td>
<td>
@Html.DisplayFor(modelItem => item.ParentPath)
</td>
<td>
@Html.DisplayFor(modelItem => item.OrderID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Url)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.NodeID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.NodeID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.NodeID">Delete</a>
</td>
</tr>
}
</tbody>
<tr><td colspan="" align="center"><pager pager-option="ViewBag.PagerOption as WeiPagerOption"></pager></td></tr>
</table>
</div>
</div>

最后生成的菜单浏览器展示效果如下:

写了很久简单三层,最近决定用一下ASP.NET MVC,最近刚了解了一下ASP.NET MVC,目前最新的算是ASP.NET Core MVC,这个例子就是刚刚安装了VS2017 RC后用ASP.NET Core MVC来实现的。学习阶段希望与各位大神共勉,有不足的地方请多多指教!谢谢!

在做完这个类子后,我觉得后续还有可以优化的地方,我是从这几个方面考虑的,希望高手给予指点:

1.这里在构建无限极分类树时我是多次调用数据库查询,如果数据量小的话想着是把数据一次取出然后传递后递归方法进行操作;由于用了EF,对于EF我也是个新手,只是刚刚会用,不知道EF本身会不会对这种类型的操作进行优化及数据缓存。

2.第二个方面是在无限极分类树数据真充好后由于每个管理页面都要调用这个树的数据,考虑要对其进行缓存,如何缓存是我下一步要考虑的方法;

3.同时每个节点的权限不同,由于每个用户角色的不同权限所能调用的菜单功能也不一致,这就存在了是为每一个用户都缓存一棵树还是全局共享一棵树的问题,显然前者是不科学的,应该是全员共享一棵树的数据,只需要在View层显示时加以权限判断就可以了。这也是我在下一步要考虑的。

后续会先解决以上提到第2和第3方面的问题,等我写好后再把代码分享出来,大家一起讨论!

C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现的更多相关文章

  1. C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制

    在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制. 关于.Net Core的缓存,官方有三种实现: 1.In Memory Cachi ...

  2. sqlalchemy tree 树形分类 无限极分类的管理。预排序树,左右值树。sqlalchemy-mptt

    简介: 无限极分类是一种比较常见的数据格式,生成组织结构,生成商品分类信息,权限管理当中的细节权限设置,都离不开无限极分类的管理. 常见的有链表式,即有一个Pid指向上级的ID,以此来设置结构.写的时 ...

  3. 无限极分类php实现—查子孙树、家谱树

    1.本文更新日期:2018/05/20 , 亲测可用,在原有基础上进行增强和 详细化 . 2.面包屑导航 和 子孙树 效果图如下: 3.代码: <?php // 无限级分类中,查家谱树(面包屑导 ...

  4. js实现无限极分类

    转载注明出处!!! 转载注明出处!!! 转载注明出处!!! 因为要实现部门通讯录,后台传来的数据是直接从数据库里拿的部门表,所以没有层级分类,只有parentId表示从属关系,所以分类的事情就交给我来 ...

  5. 夺命雷公狗ThinkPHP项目之----企业网站8之栏目的添加完善(无限极分类的完成)

    我们刚才只是完成了添加的一部分,但是我们的上级分类也不能永远都是只有一个死的嘛,所以我们需要对她进行修改: 我们先将add方法里面的数据查出来再说: 然后在模板页进行遍历: 展示效果如下所示: 虽然是 ...

  6. DotNet菜鸟入门之无限极分类(一)设计篇

    写这个教程的原因,是因为,无限极分类,在许多项目中,都用得到.而对于新手来说,不是很好理解,同时,操作上也有一些误区或者不当之处.所以我就斗胆,抛砖引玉一下,已一个常见的后台左侧频道树为例子,讲解一下 ...

  7. PHP实现菜单无限极分类

    菜单数据 这里我们的菜单数据是临时数据, 没有从数据库中查询处理,数据基本和数据库中的的相似. 数据如下: $items = array( 1 => array('id' => 1, 'p ...

  8. php无限极分类以及递归(thinkphp)

    php无限极分类: 无限极分类重点在于表的设计: 1在model中: class CatModel extends Model{ protected $cat = array(); public fu ...

  9. PHP无限极分类,多种方法|很简单,这里说的很详细,其它地方说的很不好懂

    当你学习php无限极分类的时候,大家都觉得一个字"难"我也觉得很难,所以,现在都还在看,因为工作要用到,所以,就必须得研究研究.   到网上一搜php无限极分类,很多,但好多都是一 ...

随机推荐

  1. Unity3D热更新全书-脚本(四) 用C#LightEvil搭建实际开发使用的脚本框架

    C#LightEvil之前提供了很多和Unity结合的例子,都是采用把脚本文件放置在StreamingAssets中的方法. 这样可以利用Unity的特性,放在这个目录中的CS文件会被编译器编译,我们 ...

  2. webservice3

    什么是bottom up 什么是top down 通过浏览器访问如 http://localhost:8080/HelloWS/services/HelloWSsss?wsdl  获取的 wsdl, ...

  3. Thrift架构~windows下安装和Hello World及编码引起的错误

    最近开始正式接触Thrift架构,很牛B的技术,它被apache收纳了,属于开源中的一员,呵呵. 概念: Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基 ...

  4. 品味FastDFS~第三回 项目中的FastDFS

    回到目录 包括京东,淘宝在内的几个互联网老大,在实现分布式文件存储这块都使用了FastDFS,它是一个轻量级的东西,安装与使用都很方便,服务器间通过socket进行数据通讯,无论在安全和效率上都是可以 ...

  5. CentOS6.5下安装JDK

    之前一直没有完全的总结出一篇关于Linux下安装Java的过程,今天正好就整理下. 下载jdk 如果在官网下载比较慢,那么可以到我的云盘分享上,下载jdk 1.8.0的版本: 下载地址参考链接 解压缩 ...

  6. H5常用代码:适配方案2

    前面的通过视口做适配的方案由于安卓低版本原生浏览器的存在,在许多场合不尽如人意,会在低版本安卓上出现,不缩放,手动缩放未禁止的问题. 于是出现了第二种适配方案,既然通过视口缩放可以兼容,那为什么不直接 ...

  7. Atitit apache 和guava的反射工具

    Atitit apache 和guava的反射工具 apache1 Spring的反射工具类 ReflectionUtils1 Guava 反射工具2 apache  34             7 ...

  8. SqlServer 错误1053:服务并未及时响应启动或控制请求

    sqlserver 的登录用户修改成域账户后,启动不了 解决方法: 计算器管理选择管理员组 将域账户加入到管理员组即可

  9. css 文本溢出显示省略号

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  10. 每天一个linux命令(8):cp 命令

    cp命令用来复制文件或者目录,是Linux系统中最常用的命令之一.一般情况下,shell会设置一个别名,在命令行下复制文件时,如果目标文件已经存在,就会询问是否覆盖,不管你是否使用-i参数.但是如果是 ...