ASP.NET?MVC實現(xiàn)樹形導(dǎo)航菜單
在需要處理很多分類以及導(dǎo)航的時候,樹形導(dǎo)航菜單就比較適合。例如在汽車之家上:
頁面主要分兩部分,左邊是導(dǎo)航菜單,右邊顯示對應(yīng)的內(nèi)容?,F(xiàn)在,我們就在ASP.NET MVC 4 下臨摹一個,如下:
實現(xiàn)的效果包括:
1、點擊導(dǎo)航菜單上的品牌,左側(cè)顯示該品牌下的所有車型。
2、點擊導(dǎo)航菜單上的車系,左側(cè)顯示該車系下的所有車型。
3、點擊左側(cè)上方的字母導(dǎo)航,錨點跳到導(dǎo)航菜單的對應(yīng)部分。
4、頁面加載完畢,顯示所有品牌和車系,即樹形導(dǎo)航完全展開。
5、點擊導(dǎo)航菜單上的品牌,收縮或展開對應(yīng)的車系,收縮時,品牌前面圖標為+號,展開時,品牌前面的圖片為-號。
源碼部分,在這里。
思路呢?
頁面分成左右2部分,使用Bootstrap輕松實現(xiàn):
<div class="row"> <div class="col-md-2 col-lg-2 col-sm-2"> </div> <div class="col-md-10 col-lg-10 col-sm-10"> </div> </div>
左側(cè)最上方的字母導(dǎo)航,被放在一個div中,頁面加載的時候向控制器動態(tài)請求。
品牌上方的字母歸類,比如奧迪上方的字母A,實際上是一個div。
品牌和車系放在了ul中,比如奧迪品牌以及奧迪下的奧迪A4和奧迪A6車系。車系被放在了dl中。
樹形菜單采用模版比較合適,先把數(shù)據(jù)填充到模版,再把模版追加到頁面元素。
當點擊左側(cè)樹形導(dǎo)航上的品牌或車系,右側(cè)通過iframe來呈現(xiàn)對應(yīng)的內(nèi)容。
領(lǐng)域先行。有關(guān)品牌和車系就抽象成如下的類:
public class CarCategory { public int Id { get; set; } public int ParentId { get; set; } public string Name { get; set; } public string FirstLetter { get; set; } public string AnchorName { get; set; } public int Level { get; set; } public short DelFlag { get; set; } }
有關(guān)車型就抽象成如下的類:
public class Car { public int Id { get; set; } public int PinPaiId { get; set; } public int CheXiId { get; set; } public string Name { get; set; } }
頁面左側(cè)呈現(xiàn)樹形導(dǎo)航需要向控制器請求json數(shù)據(jù),大致格式是:
首字母
錨點名稱
所有品牌
品牌編號
品牌名稱
所有車系
車系編號
車系名稱
車系下車型的總數(shù)量
貌似有3層,那就從最里面這層開始建模。有關(guān)車系在樹形導(dǎo)航中的顯示:
public class CheXiForDisplay { public int CheXiId { get; set; } public int TotalCount { get; set; } public string CheXiName { get; set; } }
有關(guān)品牌在樹形導(dǎo)航中的顯示:
public class PinPaiForDisplay { public int PinPaiId { get; set; } public string PinPaiName { get; set; } public List<CheXiForDisplay> CheXis { get; set; } }
有關(guān)品牌車系分組的:
public class PinPaiCheXiForDisplay { public string FirstLetter { get; set; } public string Anchor { get; set; } public List<PinPaiForDisplay> PinPais { get; set; } }
數(shù)據(jù)源從哪里來?模擬了一個:
public class Database { public static IEnumerable<CarCategory> GetAllCarCategories() { return new List<CarCategory> { new CarCategory(){Id = 1, ParentId = 0, Name = "奧迪",FirstLetter = "A", AnchorName = "AA", Level = 1, DelFlag = 0}, new CarCategory(){Id = 2, ParentId = 0, Name = "寶馬",FirstLetter = "B", AnchorName = "BB", Level = 1, DelFlag = 0}, new CarCategory(){Id = 3, ParentId = 0, Name = "保時捷",FirstLetter = "B", AnchorName = "BB", Level = 1, DelFlag = 0}, new CarCategory(){Id = 4, ParentId = 0, Name = "長安",FirstLetter = "C", AnchorName = "CC", Level = 1, DelFlag = 0}, new CarCategory(){Id = 5, ParentId = 0, Name = "大眾",FirstLetter = "D", AnchorName = "DD", Level = 1, DelFlag = 0}, new CarCategory(){Id = 6, ParentId = 0, Name = "東風(fēng)",FirstLetter = "D", AnchorName = "DD", Level = 1, DelFlag = 0}, new CarCategory(){Id = 7, ParentId = 0, Name = "豐田",FirstLetter = "F", AnchorName = "FF", Level = 1, DelFlag = 0}, new CarCategory(){Id = 8, ParentId = 0, Name = "福特",FirstLetter = "F", AnchorName = "FF", Level = 1, DelFlag = 0}, new CarCategory(){Id = 9, ParentId = 1, Name = "奧迪A4",FirstLetter = "A", AnchorName = "AA", Level = 2, DelFlag = 0}, new CarCategory(){Id = 10, ParentId = 1, Name = "奧迪A6",FirstLetter = "A", AnchorName = "AA", Level = 2, DelFlag = 0}, new CarCategory(){Id = 11, ParentId = 2, Name = "寶馬1",FirstLetter = "B", AnchorName = "BB", Level = 2, DelFlag = 0}, new CarCategory(){Id = 12, ParentId = 2, Name = "寶馬2",FirstLetter = "B", AnchorName = "BB", Level = 2, DelFlag = 0}, new CarCategory(){Id = 13, ParentId = 3, Name = "保時捷1",FirstLetter = "B", AnchorName = "BB", Level = 2, DelFlag = 0}, new CarCategory(){Id = 14, ParentId = 3, Name = "保時捷2",FirstLetter = "B", AnchorName = "BB", Level = 2, DelFlag = 0}, new CarCategory(){Id = 15, ParentId = 4, Name = "長安1",FirstLetter = "C", AnchorName = "CC", Level = 2, DelFlag = 0}, new CarCategory(){Id = 16, ParentId = 4, Name = "長安2",FirstLetter = "C", AnchorName = "CC", Level = 2, DelFlag = 0}, new CarCategory(){Id = 17, ParentId = 5, Name = "大眾1",FirstLetter = "D", AnchorName = "DD", Level = 2, DelFlag = 0}, new CarCategory(){Id = 18, ParentId = 5, Name = "大眾2",FirstLetter = "D", AnchorName = "DD", Level = 2, DelFlag = 1}, new CarCategory(){Id = 19, ParentId = 6, Name = "東風(fēng)1",FirstLetter = "D", AnchorName = "DD", Level = 2, DelFlag = 0}, new CarCategory(){Id = 20, ParentId = 6, Name = "東風(fēng)2",FirstLetter = "D", AnchorName = "DD", Level = 2, DelFlag = 0}, new CarCategory(){Id = 21, ParentId = 7, Name = "豐田1",FirstLetter = "F", AnchorName = "FF", Level = 2, DelFlag = 0}, new CarCategory(){Id = 22, ParentId = 7, Name = "豐田2",FirstLetter = "F", AnchorName = "FF", Level = 2, DelFlag = 0}, new CarCategory(){Id = 23, ParentId = 8, Name = "福特1",FirstLetter = "F", AnchorName = "AFF", Level = 2, DelFlag = 0}, new CarCategory(){Id = 24, ParentId = 8, Name = "福特2",FirstLetter = "F", AnchorName = "AFF", Level = 2, DelFlag = 0} }; } public static IEnumerable<Car> GetAllCars() { return new List<Car> { new Car(){Id = 1, PinPaiId = 1, CheXiId = 9, Name = "奧迪A401"}, new Car(){Id = 2, PinPaiId = 1, CheXiId = 9, Name = "奧迪A402"}, new Car(){Id = 3, PinPaiId = 1, CheXiId = 10, Name = "奧迪A601"}, new Car(){Id = 4, PinPaiId = 1, CheXiId = 10, Name = "奧迪A602"}, new Car(){Id = 5, PinPaiId = 2, CheXiId = 11, Name = "寶馬101"}, new Car(){Id = 6, PinPaiId = 2, CheXiId = 11, Name = "寶馬102"}, new Car(){Id = 7, PinPaiId = 2, CheXiId = 12, Name = "寶馬201"}, new Car(){Id = 8, PinPaiId = 2, CheXiId = 12, Name = "寶馬202"}, new Car(){Id = 9, PinPaiId = 3, CheXiId = 13, Name = "保時捷101"}, new Car(){Id = 10, PinPaiId = 3, CheXiId = 13, Name = "保時捷102"}, new Car(){Id = 11, PinPaiId = 3, CheXiId = 14, Name = "保時捷201"}, new Car(){Id = 12, PinPaiId = 3, CheXiId = 14, Name = "保時捷202"}, new Car(){Id = 13, PinPaiId = 4, CheXiId = 15, Name = "長安101"}, new Car(){Id = 14, PinPaiId = 4, CheXiId = 15, Name = "長安102"}, new Car(){Id = 15, PinPaiId = 4, CheXiId = 16, Name = "長安201"}, new Car(){Id = 16, PinPaiId = 4, CheXiId = 16, Name = "長安202"}, new Car(){Id = 17, PinPaiId = 5, CheXiId = 17, Name = "大眾101"}, new Car(){Id = 18, PinPaiId = 5, CheXiId = 17, Name = "大眾102"}, new Car(){Id = 19, PinPaiId = 5, CheXiId = 18, Name = "大眾201"}, new Car(){Id = 20, PinPaiId = 5, CheXiId = 18, Name = "大眾202"}, new Car(){Id = 21, PinPaiId = 6, CheXiId = 19, Name = "東風(fēng)101"}, new Car(){Id = 22, PinPaiId = 6, CheXiId = 19, Name = "東風(fēng)102"}, new Car(){Id = 23, PinPaiId = 6, CheXiId = 20, Name = "東風(fēng)201"}, new Car(){Id = 24, PinPaiId = 6, CheXiId = 20, Name = "東風(fēng)202"}, new Car(){Id = 25, PinPaiId = 7, CheXiId = 21, Name = "豐田101"}, new Car(){Id = 26, PinPaiId = 7, CheXiId = 21, Name = "豐田102"}, new Car(){Id = 27, PinPaiId = 7, CheXiId = 22, Name = "豐田201"}, new Car(){Id = 28, PinPaiId = 7, CheXiId = 22, Name = "豐田202"}, new Car(){Id = 29, PinPaiId = 8, CheXiId = 23, Name = "福特101"}, new Car(){Id = 30, PinPaiId = 8, CheXiId = 23, Name = "福特102"}, new Car(){Id = 31, PinPaiId = 8, CheXiId = 24, Name = "福特201"}, new Car(){Id = 32, PinPaiId = 8, CheXiId = 24, Name = "福特202"} }; } }
好,現(xiàn)在可以向控制器要數(shù)據(jù)了。
public class HomeController : Controller { public ActionResult Index() { return View(); } //獲取所有首字母以及錨點的json public ActionResult GetFirstLettersJson() { var allCarCategories = Database.GetAllCarCategories(); var result = from l in allCarCategories group l by l.FirstLetter into g select new {firstletter = g.Key, anchor=g.ToList()[0].AnchorName}; return Json(result, JsonRequestBehavior.AllowGet); } //獲取按首字母分組后的品牌車系json public ActionResult GetPinPaiCheXiJson() { var allPinPais = Database.GetAllCarCategories().Where(c => c.Level == 1).OrderBy(c => c.FirstLetter); var allPinPaisGroup = from p in allPinPais group p by new { p.FirstLetter, p.AnchorName }; List<PinPaiCheXiForDisplay> result1 = new List<PinPaiCheXiForDisplay>(); foreach (var item in allPinPaisGroup) { //品牌車系 PinPaiCheXiForDisplay pinPaiCheXiForDisplay = new PinPaiCheXiForDisplay(); pinPaiCheXiForDisplay.FirstLetter = item.Key.FirstLetter; pinPaiCheXiForDisplay.Anchor = item.Key.AnchorName; //品牌 List<PinPaiForDisplay> pinPaiForDisplays = new List<PinPaiForDisplay>(); foreach (var pinpai in item.ToList()) { PinPaiForDisplay pinPaiForDisplay = new PinPaiForDisplay(); pinPaiForDisplay.PinPaiId = pinpai.Id; pinPaiForDisplay.PinPaiName = pinpai.Name; //車系 List<CheXiForDisplay> cheXiForDisplays = new List<CheXiForDisplay>(); var cheXis = Database.GetAllCarCategories().Where(c => c.ParentId == pinpai.Id).OrderBy(c => c.Id); foreach (var chexi in cheXis) { CheXiForDisplay cheXiForDisplay = new CheXiForDisplay(); cheXiForDisplay.CheXiId = chexi.Id; cheXiForDisplay.CheXiName = chexi.Name; cheXiForDisplay.TotalCount = cheXis.Count(); cheXiForDisplays.Add(cheXiForDisplay); } pinPaiForDisplay.CheXis = cheXiForDisplays; pinPaiForDisplays.Add(pinPaiForDisplay); } pinPaiCheXiForDisplay.PinPais = pinPaiForDisplays; result1.Add(pinPaiCheXiForDisplay); } return Json(result1, JsonRequestBehavior.AllowGet); } //根據(jù)品牌Id顯示車型 public ActionResult GetCheXingsByPId(int pid) { var cars = Database.GetAllCars().Where(c => c.PinPaiId == pid); return View(cars); } //根據(jù)車系Id顯示車型 public ActionResult GetCheXingsByChexiId(int cxid) { var cars = Database.GetAllCars().Where(c => c.CheXiId == cxid); return View(cars); } }
在Shared/_Layout.cshtml中,該引用的css,js都要引用上。
<head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> <link href="~/bootstrap/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet" /> @Styles.Render("~/Content/css") @RenderSection("styles", required: false) @Scripts.Render("~/bundles/jquery") <script src="~/bootstrap/js/bootstrap.min.js"></script> </head> <body> @RenderBody() @RenderSection("scripts", required: false) </body>
Home/Index.cshtml就負責(zé)顯示就行了。
@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } @section styles { <link href="~/Content/sidemenu.css" rel="external nofollow" rel="stylesheet" /> } <div class="row"> <div class="col-md-2 col-lg-2 col-sm-2"> <!--字母導(dǎo)航開始--> <div id="lDaoHang"> </div> <!--字母導(dǎo)航結(jié)束--> <!--樹開始--> <div id="cTreeDiv" style="overflow-x: hidden; overflow-y: scroll; height: 550px; width: 99%;"> </div> <!--樹結(jié)束--> <div> <dl id="test"></dl> </div> </div> <div class="col-md-10 col-lg-10 col-sm-10"> <div class="carContent" id="carContent"> <iframe id="frameCar" src="" scrolling="no" frameborder="0" height="100%" width="100%" onload="this.height=this.contentWindow.document.documentElement.scrollHeight"></iframe> </div> </div> </div> @section scripts { <script src="~/Scripts/jquery.tmpl.min.js"></script> <script type="text/javascript"> $(function () { //加載首字母 $.getJSON('@Url.Action("GetFirstLettersJson", "Home")', function (data) { $('#firstLetterTemplate').tmpl(data).appendTo('#lDaoHang'); }); //加載所有品牌車系 $.getJSON('@Url.Action("GetPinPaiCheXiJson", "Home")', function (data) { $('#pinpaiTemplate').tmpl(data).appendTo('#cTreeDiv'); $('.pLink').each(function () { pinPaiInitialState($(this)); }); }); //隱藏ifame所在div $("#carContent").css("display", "none"); //點擊品牌 $('#cTreeDiv').on("click", ".pLink", function () { //切換 togglePinPaiState($(this)); //顯示右邊區(qū)域 var url = "/Home/GetCheXingsByPId?pid=" + $(this).attr('id'); $("#frameCar").attr("src", url); $("#carContent").css("display", "block"); }); //點擊車系 $('#cTreeDiv').on("click", ".cxLink", function () { //顯示右邊區(qū)域 var url = "/Home/GetCheXingsByChexiId?cxid=" + $(this).attr('id'); $("#frameCar").attr("src", url); $("#carContent").css("display", "block"); }); }); //品牌的初始狀態(tài),即把車系隱藏和品牌前面的圖標為+號 var pstate = 0; //品牌只有2種狀態(tài):所有車系隱藏,品牌前面的圖標變?yōu)闉?號;要么顯示品牌下的所有車系,品牌前面的圖標變?yōu)?號 //把車系隱藏和品牌前面的圖標為+號,記為狀態(tài)0 //把車系隱藏和品牌前面的圖標為-號,記為狀態(tài)1 function togglePinPaiState($pinpai) { if (pstate == 0) { var $i = $pinpai.parent().find("i"); var attr = $i.attr('class'); if (typeof attr !== typeof undefined && attr !== false) { $i.removeClass("iconHide"); } $i.addClass("iconShow"); $pinpai.parent().parent().find("dl").show(); pstate = 1; } else { var $j = $pinpai.parent().find("i"); var attr1 = $j.attr('class'); if (typeof attr1 !== typeof undefined && attr1 !== false) { $j.removeClass("iconShow"); } $j.addClass("iconHide"); $pinpai.parent().parent().find("dl").hide(); pstate = 0; } } function pinPaiInitialState($pinpai) { pstate = 0; togglePinPaiState($pinpai); } </script> <!--首字母模版--> <script id="firstLetterTemplate" type="text/x-jQuery-tmpl"> <div class="lWrapper"> <a href="#${anchor}" rel="external nofollow" class="lLink">${firstletter}</a> </div> </script> <!--品牌模版--> <script id="pinpaiTemplate" type="text/x-jQuery-tmpl"> <div class="lHeader" id="${Anchor}">${FirstLetter}</div> <ul class="uTree"> {{if PinPais}} {{each PinPais}} <li> <h5 class="font-bold"> <a href="javascript:void(0)" rel="external nofollow" rel="external nofollow" class="pLink" id="${$value.PinPaiId}"><i></i>${$value.PinPaiName}</a> </h5> <dl> {{tmpl(CheXis) "#chexiTemplate"}} </dl> </li> {{/each}} {{else}} <li>沒有對應(yīng)品牌</li> {{/if}} </ul> </script> <!--車系模版--> <script id="chexiTemplate" type="text/x-jQuery-tmpl"> <dd><a id="${CheXiId}" href="javascript:void(0)" rel="external nofollow" rel="external nofollow" class="cxLink">${CheXiName}<em>(${TotalCount})</em></a></dd> </script> }
以上,
- 從控制器返回的有關(guān)樹形菜單的json數(shù)據(jù),先填充到j(luò)query.tmpl.min.js模版中,然后追加到頁面上。
- 樹形菜單的展開或收縮,通過全局變量pstate在0和1之間的切換來實現(xiàn),頁面初次加載給變量pstate一個初始值。
另外,點擊樹形導(dǎo)航上的品牌,iframe加載的視圖是Home/GetCheXingsByPId.cshtml
@model IEnumerable<MvcApplication1.Models.Car> @{ ViewBag.Title = "GetCheXingsByPId"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>GetCheXingsByPId</h2> <div> @foreach (var item in Model) { <p>@item.Name </p> } </div>
點擊樹形導(dǎo)航上的車系,iframe加載的視圖是Home/GetCheXingsByChexiId.cshtml
@model IEnumerable<MvcApplication1.Models.Car> @{ ViewBag.Title = "GetCheXingsByChexiId"; Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>GetCheXingsByChexiId</h2> <div> @foreach (var item in Model) { <p>@item.Name </p> } </div>
就這樣。
到此這篇關(guān)于ASP.NET MVC實現(xiàn)樹形導(dǎo)航菜單的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
ASP .NET中執(zhí)行控件(如ImageButton、LinkButton等)命令不刷新頁面
在操作時,很多時候希望提交命令之后不刷新頁面:1、防止頁面拉動,2、防止主框架中刷新丟失當前運行的子界面。2009-03-03Centos7+Docker+Jenkins+ASP.NET Core 2.0自動化發(fā)布與部署的實現(xiàn)
這篇文章主要給大家介紹了關(guān)于Centos7+Docker+Jenkins+ASP.NET Core 2.0自動化發(fā)布與部署的相關(guān)資料,文中通過示例代碼及圖文介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2018-05-05.NET Core Dapper操作mysql數(shù)據(jù)庫的實現(xiàn)方法
這篇文章主要介紹了.NET Core Dapper操作mysql數(shù)據(jù)庫的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04.NET?Core利用BsonDocumentProjectionDefinition和Lookup進行?join?
這篇文章主要介紹了.NET?Core利用BsonDocumentProjectionDefinition和Lookup進行join關(guān)聯(lián)查詢,這里主要介紹一下查詢角色的所有用戶的例子,文章結(jié)合實例代碼給大家詳細講解,需要的朋友可以參考下2022-10-10asp.net 退出登陸(解決退出后點擊瀏覽器后退問題仍然可回到頁面問題)
退出登陸是再常見不過的了,先清除Session,再轉(zhuǎn)到登陸頁面2009-04-04asp.net 通過aspnetpager為DataList分頁
今天整了半天才把DataList的分頁搞定,下面把我的設(shè)計過程給大家講講2009-12-12asp.net 備份和恢復(fù)數(shù)據(jù)庫的方法示例
這篇文章主要介紹了asp.net 備份和恢復(fù)數(shù)據(jù)庫的方法示例,需要的朋友可以參考下2014-02-02.Net Core WebApi部署到Windows服務(wù)器上的步驟
這篇文章主要介紹了.Net Core WebApi部署到Windows服務(wù)器上的步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03