C#——後臺管理端多級選單的生成方式
阿新 • • 發佈:2018-11-28
現在大多的應用程式(後端)都有選單,不管是在左側還是上面,介面基本都是基於現有的UI框架或者網上找的單獨的選單的外掛。而實現的方式,大部分都是使用的AJAX形式來完成。前段時間,在總結一些過往的專案時,發現了一些不同的實現的方式,這裡想總結一下。所以也就有了這篇文章~~
我建立的測試Demo是使用的MVC的模式,選單是使用的網上找的第三方外掛,實現多級(無限)的頂部選單。直接上程式碼來說明~
開始之前,先看下css和js的引用情況以及一些需要的準備工作:
css
<link href="~/scripts/css/bootstrap.min.css" rel="stylesheet" media="screen"> <link rel="stylesheet" href="~/scripts/css/font-awesome.min.css" media="screen"> <link rel="stylesheet" href="~/scripts/css/zlight.menu.css" media="screen">
js
<script src="~/scripts/jquery-1.9.1.min.js"></script>
<script src="~/scripts/bootstrap.min.js"></script>
<script src="~/scripts/jquery.zlight.menu.1.0.min.js"></script>
<!--自定義的js,編寫自己的js生成選單-->
<script src="~/scripts/Home/home.js"></script>
模擬的資料來源
/// <summary> /// 得到資料來源 /// </summary> /// <returns></returns> private List<MenuModel> GetData() { var lstData = new List<MenuModel>(); //頂層選單 lstData.Add(new MenuModel() { Id = "1", MenuName = "Blog", MenuUrl = "#", ParentId = "#", SortNumb = 1 }); lstData.Add(new MenuModel() { Id = "2", MenuName = "Portfolio", MenuUrl = "#", ParentId = "#", SortNumb = 2 }); lstData.Add(new MenuModel() { Id = "3", MenuName = "Pages", MenuUrl = "#", ParentId = "#", SortNumb = 3 }); lstData.Add(new MenuModel() { Id = "4", MenuName = "Contact", MenuUrl = "#", ParentId = "#", SortNumb = 4 }); lstData.Add(new MenuModel() { Id = "5", MenuName = "About", MenuUrl = "#", ParentId = "#", SortNumb = 5 }); //第二層 lstData.Add(new MenuModel() { Id = "11", MenuName = "LINK1", MenuUrl = "#", ParentId = "1", SortNumb = 1 }); lstData.Add(new MenuModel() { Id = "12", MenuName = "LINK2", MenuUrl = "#", ParentId = "1", SortNumb = 2 }); lstData.Add(new MenuModel() { Id = "13", MenuName = "LINK3", MenuUrl = "#", ParentId = "1", SortNumb = 3 }); lstData.Add(new MenuModel() { Id = "31", MenuName = "LINK1", MenuUrl = "#", ParentId = "3", SortNumb = 1 }); lstData.Add(new MenuModel() { Id = "32", MenuName = "DROPDOWN", MenuUrl = "#", ParentId = "3", SortNumb = 2 }); lstData.Add(new MenuModel() { Id = "33", MenuName = "LINK2", MenuUrl = "#", ParentId = "3", SortNumb = 3 }); //第三層 lstData.Add(new MenuModel() { Id = "321", MenuName = "LINK1", MenuUrl = "#", ParentId = "32", SortNumb = 1 }); lstData.Add(new MenuModel() { Id = "322", MenuName = "LINK2", MenuUrl = "#", ParentId = "32", SortNumb = 2 }); lstData.Add(new MenuModel() { Id = "323", MenuName = "LINK3", MenuUrl = "#", ParentId = "32", SortNumb = 3 }); lstData.Add(new MenuModel() { Id = "324", MenuName = "DROPDOWN", MenuUrl = "#", ParentId = "32", SortNumb = 4 }); //第四層 lstData.Add(new MenuModel() { Id = "3241", MenuName = "LINK1", MenuUrl = "#", ParentId = "324", SortNumb = 1 }); lstData.Add(new MenuModel() { Id = "3242", MenuName = "LINK2", MenuUrl = "#", ParentId = "324", SortNumb = 2 }); return lstData; }
後臺選單實現需要的方法
/// <summary> /// 生成選單拼接字串 /// </summary> /// <returns></returns> private string GenerateMenu() { StringBuilder sb = new StringBuilder(); var lstAll = GetData(); var lstParent = lstAll.FindAll(x => x.ParentId == "#").ToList(); var lstChilds = lstAll.FindAll(x => x.ParentId != "#").ToList(); if (lstParent.Any()) { foreach (var top in lstParent) { var lstOnes = lstChilds.FindAll(x => x.ParentId == top.Id).OrderBy(x => x.SortNumb).ToList(); if (lstOnes.Any()) { sb.Append("<li class=\"zlight-dropdown\">") .AppendFormat("<a href = \"{0} \"> {1}<i class=\"icon-angle-down\"></i></a>", top.MenuUrl, top.MenuName) .Append("<ul class=\"zlight-submenu\">"); GetChild(sb, lstChilds, lstOnes); sb.Append("</ul></li > "); } else { sb.AppendFormat("<li><a href = \"{0} \"> {1} </a></li>", top.MenuUrl, top.MenuName); } } } return sb.ToString(); } /// <summary> /// 得到子選單項 /// </summary> /// <param name="sb">StrignBuilder物件</param> /// <param name="lstChilds">所有子節點集合</param> /// <param name="lstOnes">“父”節點集合</param> private static void GetChild(StringBuilder sb, List<MenuModel> lstChilds, List<MenuModel> lstOnes) { foreach (var chld in lstOnes) { var lstTwos = lstChilds.FindAll(x => x.ParentId == chld.Id).OrderBy(x => x.SortNumb).ToList(); if (lstTwos.Any()) { sb.Append("<li class=\"zlight-dropdown\">") .AppendFormat("<a href = \"{0} \"> {1}<i class=\"icon-angle-down\"></i></a>", chld.MenuUrl, chld.MenuName) .Append(" <ul class=\"zlight-submenu\">"); GetChild(sb, lstChilds, lstTwos); sb.Append("</ul></li> "); } else { sb.AppendFormat("<li><a href = \"{0} \" target = \"_blank\"> {1} </a></li>", chld.MenuUrl, chld.MenuName); } } }
1、Ajax方式
html部分
<div class="row">
<div class="col-lg-12">
<h4>第一種(AJAX):</h4>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<nav id="zlight-nav">
<ul id="zlight-main-nav">
<li class="zlight-active"><a href="/">Home</a></li>
</ul>
<!-- MOBILE NAV -->
<div id="zlight-mobile-nav">
<span>Menu</span>
<i class="icon-reorder zlight-icon"></i>
<select></select>
</div>
</nav> <!-- nav close -->
</div>
</div>
js(注意放到頁面載入完成事件中)
$.ajax({
url: "/Home/GetTopMenu",
type: 'POST',
async: false,
dataType: 'text',
timeout: 20000,
error: function () {
alert('Error loading XML document');
},
success: function (result) {
$("#zlight-main-nav").append(result);
$('#zlight-nav').zlightMenu();
}
});
後臺的Action方法
[HttpPost]
public ActionResult GetTopMenu()
{
return Content(GenerateMenu());
}
2、ViewBag方式
html部分
<div class="row">
<div class="col-lg-12">
<h4>第二種(ViewBag):</h4>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<nav id="zlight-nav" class="razer">
<ul id="zlight-main-nav">
<li class="zlight-active"><a href="/">Home</a></li>
@Html.Raw(@ViewBag.TopMenu)
</ul>
<!-- MOBILE NAV -->
<div id="zlight-mobile-nav">
<span>Menu</span>
<i class="icon-reorder zlight-icon"></i>
<select></select>
</div>
</nav>
</div>
</div>
js
$('.razer').zlightMenu();
後臺程式碼
// GET: Home
public ActionResult Index()
{
ViewBag.TopMenu = GenerateMenu();
return View();
}
3、Razer遞迴方式(很少用)
html部分
<div class="row">
<div class="col-lg-12">
<h4>第三種(Razer遞迴):</h4>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<nav id="zlight-nav" class="razerdigui">
<ul id="zlight-main-nav">
<li class="zlight-active"><a href="/">Home</a></li>
@{
var lstData = ViewBag.MenuDataList as List<MenuModel>;
@helper DisplayChildMenu(List<MenuModel> lstChilds, List<MenuModel> lstOnes)
{
foreach (var chld in lstOnes)
{
var lstTwos = lstChilds.FindAll(x => x.ParentId == chld.Id).OrderBy(x => x.SortNumb).ToList();
if (lstTwos.Any())
{
<li class="zlight-dropdown">
<a href="@chld.MenuUrl" target="_blank">@chld.MenuName <i class="icon-angle-down"></i></a>
<ul class="zlight-submenu">
@DisplayChildMenu(lstChilds, lstTwos)
</ul>
</li>
}
else
{
<li><a href="@chld.MenuUrl" target="_blank">@chld.MenuName</a></li>
}
}
}
var lstParent = lstData.FindAll(x => x.ParentId == "#").ToList();
var lstChilds = lstData.FindAll(x => x.ParentId != "#").ToList();
if (lstParent.Any())
{
foreach (var top in lstParent)
{
var lstOnes = lstChilds.FindAll(x => x.ParentId == top.Id).OrderBy(x => x.SortNumb).ToList();
if (lstOnes.Any())
{
<li class="zlight-dropdown">
<a href="@top.MenuUrl">@top.MenuName <i class="icon-angle-down"></i></a>
<ul class="zlight-submenu">
@DisplayChildMenu(lstChilds, lstOnes)
</ul>
</li>
}
else
{
<li><a href="@top.MenuUrl">@top.MenuName</a></li>
}
}
}
}
</ul>
<!-- MOBILE NAV -->
<div id="zlight-mobile-nav">
<span>Menu</span>
<i class="icon-reorder zlight-icon"></i>
<select></select>
</div>
</nav>
</div>
</div>
js部分
$('.razerdigui').zlightMenu();
後臺部分
// GET: Home
public ActionResult Index()
{
ViewBag.MenuDataList = GetData();
return View();
}
後記:在非MVC模式下,第一中Ajax方式是非常常用的,即使在MVC模式下仍常用。第二種和第三中在MVC模式下用都可以,Razer的遞迴之前並沒有注意到,一次突發奇想就度娘了下,結果還真有。至於需要用哪種,看個人吧