在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
最近做项目要实现一个分类的Category,点击第一级的节点出现此节点的下级节点,依次向下。这个功能的JQuery版本在js功能整理中已经有了,这里讲的是纯C#代码的实 现,还是有点难度的,现在来说一下我的实现方式吧。 首先是这种数据库方面,基本字段就是CategoryId(自增),ParentId,CategoryName,这三个是主要字段,CategoryName自不必说,然后CategoryId就是他的子节点的 ParentId,第一级节点的ParentId为0。 在程序中我们构建的ViewModel是这样的:
public class VMCategory { /// <summary> /// CategoryId /// </summary> public int CategoryId { get; set; } /// <summary> /// ParentId /// </summary> public int? ParentId { get; set; } /// <summary> /// CategoryName /// </summary> public string CategoryName { get; set; } /// <summary> /// 用来高亮被点击的节点 /// </summary> public string HighLight { get; set; } /// <summary> /// 下级节点集合 /// </summary> public List<VMCategory> CategoryNext { get; set; } } 现在有了我们的ViewModel,就要看具体的实现方法了,我们写了一个帮助类,通过给到的CategoryId来获得我们所需要的Category集合。 这里使用的是逐级附加的方式来实现对于整个Category列表的获取的。 首先添加一个总的List<VMCategory>叫finallyCategory,这个就是最终我们要返回的Category集合。 下面向finallyCategory内添加数据,我们分两部分来完成,第一步是添加非第一级Category的数据,第二步是添加Category的数据。 一:下级节点集合不是第一级节点 while(categoryId!=0) { 1.根据节点的categoryId,获取到此节点的子节点集合,依次添加到临时的List<VMCategory> temporaryCategory中,如果(finallyCategory的父节点)==(当前节点的categoryId),此节点的CategoryNext=finallyCategory 2.将categoryId改成子节点的parentId,用来搜索当前节点的父节点的子节点,即他的兄弟节点 3.将temporaryCategory赋值给finallyCategory } 二:下级节点集合是第一级节点(categoryId==0) 1.获取第一级节点集合,依次添加到临时的List<VMCategory> levelTopCategory中,如果(finallyCategory的父节点)==(当前节点的categoryId),此节点的CategoryNext=finallyCategory 2.将temporaryCategory赋值给finallyCategory 具体的代码实现如下:
public static List<VMCategory> GetCategoryListTest(int categoryId, CategoryBLL bll) { List<VMCategory> finallyCategory = new List<VMCategory>(); while (categoryId != 0) { List<VMCategory> temporaryCategory = new List<VMCategory>(); var cycleCategory = bll.RetriveByParentID(categoryId); if (categoryId != 0) categoryId = bll.RetriveByCategoryID(categoryId).FirstOrDefault().ParentID ?? 0; foreach (var c in cycleCategory) { VMCategory vmCategory = new VMCategory { CategoryId = c.CategoryID, CategoryName = c.CategoryName, ParentId = c.ParentID, CategoryNext = null, HighLight = "" }; if (finallyCategory.Count() != 0) { int cycleId = finallyCategory.FirstOrDefault().ParentId ?? 0; if (cycleId == c.CategoryID) { vmCategory.CategoryNext = finallyCategory; } } temporaryCategory.Add(vmCategory); } finallyCategory = temporaryCategory; } List<VMCategory> levelTopCategory = new List<VMCategory>(); foreach (var c in bll.RetriveByParentID(categoryId)) { VMCategory vmCategory = new VMCategory { CategoryId = c.CategoryID, CategoryName = c.CategoryName, ParentId = c.ParentID, CategoryNext = null }; if (finallyCategory.Count() != 0) { int cycleId = finallyCategory.FirstOrDefault().ParentId ?? 0; if (cycleId == c.CategoryID) { vmCategory.CategoryNext = finallyCategory; } } levelTopCategory.Add(vmCategory); } finallyCategory = levelTopCategory; return finallyCategory ; } View:
<ul style="padding-left: 3px;"> @foreach (var levelOne in Model.LeftCategory) { <li style="margin-top:5px;"> <a class="@levelOne.HighLight" href="@Url.Action("GetCategoryOrProductLeft", "Category", new { categoryid = @levelOne.CategoryId })" id="@levelOne.CategoryId">@levelOne.CategoryName</a> @if (levelOne.CategoryNext != null) { <ul> @foreach (var levelTwo in levelOne.CategoryNext) { <li style="margin-top:5px;"> <a class="@levelTwo.HighLight" href="@Url.Action("GetCategoryOrProductLeft", "Category", new { categoryid = @levelTwo.CategoryId })" id="@levelTwo.CategoryId">@levelTwo.CategoryName</a> @if (levelTwo.CategoryNext != null) { <ul> @foreach (var levelThree in levelTwo.CategoryNext) { <li style="margin-top:5px;"> <a class="@levelThree.HighLight" href="@Url.Action("GetCategoryOrProductLeft", "Category", new { categoryid = @levelThree.CategoryId })" id="@levelThree.CategoryId">@levelThree.CategoryName</a> @if (levelThree.CategoryNext != null) { <ul> @foreach (var levelFour in levelThree.CategoryNext) { <li style="margin-top:5px;"> <a class="@levelFour.HighLight" href="@Url.Action("GetCategoryOrProductLeft", "Category", new { categoryid = @levelFour.CategoryId })" id="@levelFour.CategoryId">@levelFour.CategoryName</a> </li> } </ul> } </li> } </ul> } </li> } </ul> } </li> } </ul>
这样的写法在前台赋值的时候有一个弊端,就是需要知道分类的最大层级是多少,才能去写几个循环,但是应为一般的category分类都不会太多,即使是添加分类,只是需要修改一下前台的view页面即可,可维护性还好。后期有新的改动,再做修改。 2013-6-8 修改,对于前台一大堆html的循环做了新的修改。一个递归的方法,用来形成html的StringBulider,最后被一个HtmlHelper的扩展方法调用,返回html代码。代码如下:(扩展方法没写) private static StringBuilder CreateCategoryString(List<VMCategory> vmCategory, string requrl, int CategoryID=1) { StringBuilder tagul = new StringBuilder("<ul>");//创建<ul>标签 foreach(var v in vmCategory) { TagBuilder tagli = new TagBuilder("li");//创建<ul>标签 tagli.MergeAttribute("style", "margin-top:5px; list-style:none;"); TagBuilder taga = new TagBuilder("a");//创建<a>标签 taga.MergeAttribute("class", v.CategoryId == CategoryID ? "CategoryHighLight" :v.HighLight); taga.MergeAttribute("href", requrl + "/" + v.CategoryId.ToString()); taga.MergeAttribute("id",v.CategoryId.ToString()); taga.InnerHtml=v.CategoryName; tagul.Append(tagli.ToString()+taga.ToString()); //如果 v 含有子集 if(v.CategoryNext!=null) { tagul.Append(CreateCategoryString(v.CategoryNext, requrl, CategoryID)); } } tagul.Append("</ul>"); return tagul; } 这样的话,前台的调用就只需要一句代码 @Html.CategoryShow(Model.LeftCategory,Url.Action("GetCategoryOrProductLeft","Category"),-1) 第一个参数代表传回的CategoryList,第二个参数是不带categoryId的url地址,用来在方法里加工形成每个a标签的url的,第三个是被点击的categoryid,用来高亮category的。
|
请发表评论